killbill-memoizeit

Merge remote-tracking branch 'killbill/work-for-release-0.19.x'

5/23/2018 4:19:03 PM

Changes

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

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

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

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

catalog/src/test/java/org/killbill/billing/catalog/TestLimits.java 107(+0 -107)

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

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

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

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

NEWS 5(+5 -0)

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

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

pom.xml 4(+2 -2)

profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceNotification.java 58(+0 -58)

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

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

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

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

Details

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

diff --git a/account/pom.xml b/account/pom.xml
index 1dc6009..f60a1e3 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>

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

diff --git a/api/pom.xml b/api/pom.xml
index fe60cf3..eb96d0d 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>

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

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 95a0665..c6f8d74 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
index e3d7799..2c9aa27 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
@@ -74,6 +74,10 @@ public class TestPublicBus extends TestIntegrationBase {
     @Override
     @BeforeMethod(groups = "slow")
     public void beforeMethod() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
+
         /*
         We copy the initialization instead of invoking the super method so we can add the registration
         of the publicBus event;
@@ -107,6 +111,10 @@ public class TestPublicBus extends TestIntegrationBase {
 
     @AfterMethod(groups = "slow")
     public void afterMethod() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
+
         externalBus.unregister(publicListener);
         super.afterMethod();
     }
@@ -180,7 +188,7 @@ public class TestPublicBus extends TestIntegrationBase {
                 event.getEventType() == ExtBusEventType.SUBSCRIPTION_UNCANCEL ||
                 event.getEventType() == ExtBusEventType.SUBSCRIPTION_BCD_CHANGE) {
                 try {
-                    final SubscriptionMetadata obj = (SubscriptionMetadata) mapper.readValue(event.getMetaData(), SubscriptionMetadata.class);
+                    final SubscriptionMetadata obj = mapper.readValue(event.getMetaData(), SubscriptionMetadata.class);
                     Assert.assertNotNull(obj.getBundleExternalKey());
                     Assert.assertNotNull(obj.getActionType());
                 } catch (final JsonParseException e) {
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
index c6a2b73..db8c664 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
@@ -119,6 +119,10 @@ public class TestWithInvoicePlugin extends TestIntegrationBase {
 
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
+
         testInvoicePluginApi.additionalInvoiceItem = null;
         testInvoicePluginApi.shouldAddTaxItem = true;
         testInvoicePluginApi.isAborted = false;

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

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 6f4c027..71127c8 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
index db734df..ed0e394 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project 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:
  *
@@ -77,14 +79,14 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
     private DefaultUnit[] units;
 
     @XmlElementWrapper(name = "products", required = true)
-    @XmlElement(type=DefaultProduct.class, name = "product", required = false)
+    @XmlElement(type = DefaultProduct.class, name = "product", required = false)
     private CatalogEntityCollection<Product> products;
 
     @XmlElement(name = "rules", required = true)
     private DefaultPlanRules planRules;
 
     @XmlElementWrapper(name = "plans", required = true)
-    @XmlElement(type=DefaultPlan.class, name = "plan", required = false)
+    @XmlElement(type = DefaultPlan.class, name = "plan", required = false)
     private CatalogEntityCollection<Plan> plans;
 
     @XmlElement(name = "priceLists", required = true)
@@ -101,35 +103,35 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         this.effectiveDate = effectiveDate;
     }
 
-    /* (non-Javadoc)
-      * @see org.killbill.billing.catalog.ICatalog#getCalalogName()
-      */
     @Override
     public String getCatalogName() {
         return catalogName;
     }
 
+    public StandaloneCatalog setCatalogName(final String catalogName) {
+        this.catalogName = catalogName;
+        return this;
+    }
+
     @Override
     public Date getEffectiveDate() {
         return effectiveDate;
     }
 
-    /* (non-Javadoc)
-     * @see org.killbill.billing.catalog.ICatalog#getProducts()
-     */
+    public StandaloneCatalog setEffectiveDate(final Date effectiveDate) {
+        this.effectiveDate = effectiveDate;
+        return this;
+    }
+
     @Override
     public Collection<Product> getCurrentProducts() {
         return products.getEntries();
     }
 
-
-    public CatalogEntityCollection<Product>  getCatalogEntityCollectionProduct() {
+    public CatalogEntityCollection<Product> getCatalogEntityCollectionProduct() {
         return products;
     }
 
-    /* (non-Javadoc)
-     * @see org.killbill.billing.catalog.ICatalog#getProducts()
-     */
     @Override
     public DefaultUnit[] getCurrentUnits() {
         return units;
@@ -140,21 +142,18 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return supportedCurrencies;
     }
 
-
-
     @Override
     public Collection<Plan> getCurrentPlans() {
         return plans.getEntries();
     }
 
-
     public CatalogEntityCollection<Plan> getCatalogEntityCollectionPlan() {
         return plans;
     }
 
     public boolean isTemplateCatalog() {
-        return (products == null || products.size() == 0) &&
-               (plans == null || plans.size() == 0) &&
+        return (products == null || products.isEmpty()) &&
+               (plans == null || plans.isEmpty()) &&
                (supportedCurrencies == null || supportedCurrencies.length == 0);
     }
 
@@ -166,6 +165,11 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return planRules;
     }
 
+    public StandaloneCatalog setPlanRules(final DefaultPlanRules planRules) {
+        this.planRules = planRules;
+        return this;
+    }
+
     public DefaultPriceList findCurrentPriceList(final String priceListName) throws CatalogApiException {
         return priceLists.findPriceListFrom(priceListName);
     }
@@ -174,9 +178,11 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return this.priceLists;
     }
 
-    /* (non-Javadoc)
-      * @see org.killbill.billing.catalog.ICatalog#getPlan(java.lang.String, java.lang.String)
-      */
+    public StandaloneCatalog setPriceLists(final DefaultPriceListSet priceLists) {
+        this.priceLists = priceLists;
+        return this;
+    }
+
     @Override
     public Plan createOrFindCurrentPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext unused) throws CatalogApiException {
         final Plan result;
@@ -195,7 +201,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         }
         if (result == null) {
             throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND,
-                                          spec.getPlanName() !=  null ? spec.getPlanName() : "undefined",
+                                          spec.getPlanName() != null ? spec.getPlanName() : "undefined",
                                           spec.getProductName() != null ? spec.getProductName() : "undefined",
                                           spec.getBillingPeriod() != null ? spec.getBillingPeriod() : "undefined",
                                           spec.getPriceListName() != null ? spec.getPriceListName() : "undefined");
@@ -203,6 +209,12 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return result;
     }
 
+    //////////////////////////////////////////////////////////////////////////////
+    //
+    // RULES
+    //
+    //////////////////////////////////////////////////////////////////////////////
+
     @Override
     public DefaultPlan findCurrentPlan(final String name) throws CatalogApiException {
         if (name == null || plans == null) {
@@ -246,16 +258,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return priceLists.findPriceListFrom(name);
     }
 
-    //////////////////////////////////////////////////////////////////////////////
-    //
-    // RULES
-    //
-    //////////////////////////////////////////////////////////////////////////////
-    @Override
-    public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier from, final PlanSpecifier to) throws CatalogApiException {
-        return planRules.getPlanChangePolicy(from, to, this);
-    }
-
     @Override
     public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier from, final PlanSpecifier to) throws CatalogApiException {
         return planRules.getPlanChangeAlignment(from, to, this);
@@ -276,6 +278,12 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return planRules.getBillingAlignment(planPhase, this);
     }
 
+    //////////////////////////////////////////////////////////////////////////////
+    //
+    // UNIT LIMIT
+    //
+    //////////////////////////////////////////////////////////////////////////////
+
     @Override
     public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to)
             throws CatalogApiException {
@@ -284,8 +292,8 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 
     @Override
     public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
-        validateCollection(catalog, errors, (DefaultProduct[])  products.toArray(new DefaultProduct[products.size()]));
-        validateCollection(catalog, errors, (DefaultPlan[])  plans.toArray(new DefaultPlan[plans.size()]));
+        validateCollection(catalog, errors, (DefaultProduct[]) products.toArray(new DefaultProduct[0]));
+        validateCollection(catalog, errors, (DefaultPlan[]) plans.toArray(new DefaultPlan[0]));
         priceLists.validate(catalog, errors);
         planRules.validate(catalog, errors);
         return errors;
@@ -304,7 +312,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
             cur.initialize(catalog, sourceURI);
         }
         for (final Product p : products.getEntries()) {
-            ((DefaultProduct)p).initialize(catalog, sourceURI);
+            ((DefaultProduct) p).initialize(catalog, sourceURI);
         }
         for (final Plan p : plans.getEntries()) {
             ((DefaultPlan) p).initialize(catalog, sourceURI);
@@ -315,16 +323,9 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return recurringBillingMode;
     }
 
-    //////////////////////////////////////////////////////////////////////////////
-    //
-    // UNIT LIMIT
-    //
-    //////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public boolean compliesWithLimits(final String phaseName, final String unit, final double value) throws CatalogApiException {
-        PlanPhase phase = findCurrentPhase(phaseName);
-        return phase.compliesWithLimits(unit, value);
+    public StandaloneCatalog setRecurringBillingMode(final BillingMode recurringBillingMode) {
+        this.recurringBillingMode = recurringBillingMode;
+        return this;
     }
 
     public StandaloneCatalog setProducts(final Iterable<Product> products) {
@@ -342,60 +343,24 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return this;
     }
 
-    public StandaloneCatalog setCatalogName(final String catalogName) {
-        this.catalogName = catalogName;
-        return this;
-    }
-
-    public StandaloneCatalog setEffectiveDate(final Date effectiveDate) {
-        this.effectiveDate = effectiveDate;
-        return this;
-    }
-
-    public StandaloneCatalog setRecurringBillingMode(final BillingMode recurringBillingMode) {
-        this.recurringBillingMode = recurringBillingMode;
-        return this;
-    }
-
-    public StandaloneCatalog setPlanRules(final DefaultPlanRules planRules) {
-        this.planRules = planRules;
-        return this;
-    }
-
-    public StandaloneCatalog setPriceLists(final DefaultPriceListSet priceLists) {
-        this.priceLists = priceLists;
-        return this;
-    }
-
     public StandaloneCatalog setUnits(final DefaultUnit[] units) {
         this.units = units;
         return this;
     }
 
     @Override
-    public boolean canCreatePlan(final PlanSpecifier specifier) throws CatalogApiException {
-        final Product product = findCurrentProduct(specifier.getProductName());
-        final Plan plan = createOrFindCurrentPlan(specifier, null);
-        final DefaultPriceList priceList = findCurrentPriceList(specifier.getPriceListName());
-
-        return (product != null) &&
-               (plan != null) &&
-               (priceList != null);
-    }
-
-    @Override
     public List<Listing> getAvailableAddOnListings(final String baseProductName, @Nullable final String priceListName) {
         final List<Listing> availAddons = new ArrayList<Listing>();
 
         try {
-            Product product = findCurrentProduct(baseProductName);
+            final Product product = findCurrentProduct(baseProductName);
             if (product != null) {
-                for (Product availAddon : product.getAvailable()) {
-                    for (BillingPeriod billingPeriod : BillingPeriod.values()) {
-                        for (PriceList priceList : getPriceLists().getAllPriceLists()) {
+                for (final Product availAddon : product.getAvailable()) {
+                    for (final BillingPeriod billingPeriod : BillingPeriod.values()) {
+                        for (final PriceList priceList : getPriceLists().getAllPriceLists()) {
                             if (priceListName == null || priceListName.equals(priceList.getName())) {
-                                Collection<Plan> addonInList = priceList.findPlans(availAddon, billingPeriod);
-                                for (Plan cur : addonInList) {
+                                final Collection<Plan> addonInList = priceList.findPlans(availAddon, billingPeriod);
+                                for (final Plan cur : addonInList) {
                                     availAddons.add(new DefaultListing(cur, priceList));
                                 }
                             }
@@ -403,7 +368,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
                     }
                 }
             }
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             // No such product - just return an empty list
         }
         return availAddons;
@@ -413,10 +378,10 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
     public List<Listing> getAvailableBasePlanListings() {
         final List<Listing> availBasePlans = new ArrayList<Listing>();
 
-        for (Plan plan : getCurrentPlans()) {
+        for (final Plan plan : getCurrentPlans()) {
             if (plan.getProduct().getCategory().equals(ProductCategory.BASE)) {
-                for (PriceList priceList : getPriceLists().getAllPriceLists()) {
-                    for (Plan priceListPlan : priceList.getPlans()) {
+                for (final PriceList priceList : getPriceLists().getAllPriceLists()) {
+                    for (final Plan priceListPlan : priceList.getPlans()) {
                         if (priceListPlan.getName().equals(plan.getName()) &&
                             priceListPlan.getProduct().getName().equals(plan.getProduct().getName())) {
                             availBasePlans.add(new DefaultListing(priceListPlan, priceList));
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index 32018fd..6e171ad 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project 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
@@ -44,7 +44,6 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingAlignment;
-import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
@@ -123,54 +122,30 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
         // This is not strictly correct from an api point of view, but there is no real good use case
         // where the system would ask for the catalog for a date prior any catalog was uploaded and
         // yet time manipulation could end of inn that state -- see https://github.com/killbill/killbill/issues/760
-        if (versions.size() > 0) {
+        if (!versions.isEmpty()) {
             return 0;
         }
         throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, date.toString());
     }
 
-    private class PlanRequestWrapper {
-
-        private final PlanSpecifier spec;
-        private final PlanPhasePriceOverridesWithCallContext overrides;
-
-        public PlanRequestWrapper(final String planName) {
-            this.spec = new PlanSpecifier(planName);
-            this.overrides = null;
-        }
-
-        public PlanRequestWrapper(final PlanSpecifier spec,
-                                  final PlanPhasePriceOverridesWithCallContext overrides) {
-            this.spec = spec;
-            this.overrides = overrides;
-        }
-
-
-        public Plan findPlan(final StandaloneCatalog catalog) throws CatalogApiException {
-            return catalog.createOrFindCurrentPlan(spec, overrides);
-        }
-
-        public PlanSpecifier getSpec() {
-            return spec;
-        }
-    }
-
     private CatalogPlanEntry findCatalogPlanEntry(final PlanRequestWrapper wrapper,
                                                   final DateTime requestedDate,
-                                                  final DateTime subscriptionStartDate)
-            throws CatalogApiException {
+                                                  final DateTime subscriptionStartDate) throws CatalogApiException {
         final List<StandaloneCatalog> catalogs = versionsBeforeDate(requestedDate.toDate());
         if (catalogs.isEmpty()) {
             throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, requestedDate.toDate().toString());
         }
 
+        CatalogPlanEntry candidateInSubsequentCatalog = null;
         for (int i = catalogs.size() - 1; i >= 0; i--) { // Working backwards to find the latest applicable plan
             final StandaloneCatalog c = catalogs.get(i);
+
             final Plan plan;
             try {
                 plan = wrapper.findPlan(c);
             } catch (final CatalogApiException e) {
-                if (e.getCode() != ErrorCode.CAT_NO_SUCH_PLAN.getCode()) {
+                if (e.getCode() != ErrorCode.CAT_NO_SUCH_PLAN.getCode() &&
+                    e.getCode() != ErrorCode.CAT_PLAN_NOT_FOUND.getCode()) {
                     throw e;
                 } else {
                     // If we can't find an entry it probably means the plan has been retired so we keep looking...
@@ -178,22 +153,29 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
                 }
             }
 
-
-            final boolean initialVersion = (i == 0);
+            final boolean oldestCatalog = (i == 0);
             final DateTime catalogEffectiveDate = CatalogDateHelper.toUTCDateTime(c.getEffectiveDate());
-            if (initialVersion || // Prevent issue with time granularity -- see #760
-                !subscriptionStartDate.isBefore(catalogEffectiveDate)) { // It's a new subscription this plan always applies
+            final boolean catalogOlderThanSubscriptionStartDate = !subscriptionStartDate.isBefore(catalogEffectiveDate);
+            if (oldestCatalog || // Prevent issue with time granularity -- see #760
+                catalogOlderThanSubscriptionStartDate) { // It's a new subscription, this plan always applies
                 return new CatalogPlanEntry(c, plan);
-            } else { //Its an existing subscription
-                if (plan.getEffectiveDateForExistingSubscriptions() != null) { //if it is null any change to this does not apply to existing subscriptions
+            } else { // It's an existing subscription
+                if (plan.getEffectiveDateForExistingSubscriptions() != null) { // If it is null, any change to this catalog does not apply to existing subscriptions
                     final DateTime existingSubscriptionDate = CatalogDateHelper.toUTCDateTime(plan.getEffectiveDateForExistingSubscriptions());
-                    if (requestedDate.isAfter(existingSubscriptionDate)) { // this plan is now applicable to existing subs
+                    if (requestedDate.isAfter(existingSubscriptionDate)) { // This plan is now applicable to existing subs
                         return new CatalogPlanEntry(c, plan);
                     }
+                } else if (candidateInSubsequentCatalog == null) {
+                    // Keep the most recent one
+                    candidateInSubsequentCatalog = new CatalogPlanEntry(c, plan);
                 }
             }
         }
 
+        if (candidateInSubsequentCatalog != null) {
+            return candidateInSubsequentCatalog;
+        }
+
         final PlanSpecifier spec = wrapper.getSpec();
         throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND,
                                       spec.getPlanName() != null ? spec.getPlanName() : "undefined",
@@ -202,26 +184,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
                                       spec.getPriceListName() != null ? spec.getPriceListName() : "undefined");
     }
 
-    private static class CatalogPlanEntry {
-
-        private final StaticCatalog staticCatalog;
-        private final Plan plan;
-
-        public CatalogPlanEntry(final StaticCatalog staticCatalog, final Plan plan) {
-            this.staticCatalog = staticCatalog;
-            this.plan = plan;
-        }
-
-        public StaticCatalog getStaticCatalog() {
-            return staticCatalog;
-        }
-
-        public Plan getPlan() {
-            return plan;
-        }
-    }
-
-
     public Clock getClock() {
         return clock;
     }
@@ -233,13 +195,13 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     //
     // Public methods not exposed in interface
     //
-    public void addAll(final List<StandaloneCatalog> inputVersions) throws CatalogApiException {
+    public void addAll(final Iterable<StandaloneCatalog> inputVersions) {
         for (final StandaloneCatalog cur : inputVersions) {
             add(cur);
         }
     }
 
-    public void add(final StandaloneCatalog e) throws CatalogApiException {
+    public void add(final StandaloneCatalog e) {
         if (catalogName == null && e.getCatalogName() != null) {
             catalogName = e.getCatalogName();
         }
@@ -260,9 +222,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
         return versions.size();
     }
 
-    //
-    // Simple getters
-    //
     @Override
     public String getCatalogName() {
         return catalogName;
@@ -293,9 +252,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
         return versionForDate(requestedDate).getPriceLists();
     }
 
-    //
-    // Find a plan
-    //
     @Override
     public Plan findPlan(final String name,
                          final DateTime requestedDate)
@@ -326,21 +282,15 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
                                  final DateTime requestedDate,
                                  final DateTime subscriptionStartDate)
             throws CatalogApiException {
-        final CatalogPlanEntry entry =  findCatalogPlanEntry(new PlanRequestWrapper(spec, overrides), requestedDate, subscriptionStartDate);
+        final CatalogPlanEntry entry = findCatalogPlanEntry(new PlanRequestWrapper(spec, overrides), requestedDate, subscriptionStartDate);
         return entry.getPlan();
     }
 
-    //
-    // Find a product
-    //
     @Override
     public Product findProduct(final String name, final DateTime requestedDate) throws CatalogApiException {
         return versionForDate(requestedDate).findCurrentProduct(name);
     }
 
-    //
-    // Find a phase
-    //
     @Override
     public PlanPhase findPhase(final String phaseName,
                                final DateTime requestedDate,
@@ -351,9 +301,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
         return plan.findPhase(phaseName);
     }
 
-    //
-    // Find a price list associated to a given subscription
-    //
     @Override
     public PriceList findPriceListForPlan(final String planName,
                                           final DateTime requestedDate,
@@ -363,58 +310,55 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
         return entry.getStaticCatalog().findCurrentPricelist(entry.getPlan().getPriceListName());
     }
 
-
-    public PriceList findPriceList(final String name, final DateTime requestedDate)
-            throws CatalogApiException {
-        return versionForDate(requestedDate).findCurrentPriceList(name);
-    }
-
-
-    //
-    // Rules
-    //
-    @Override
-    public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier from,
-                                                final PlanSpecifier to, final DateTime requestedDate) throws CatalogApiException {
-        return versionForDate(requestedDate).planChangePolicy(from, to);
-    }
-
     @Override
-    public BillingActionPolicy planCancelPolicy(final PlanPhaseSpecifier planPhase, final DateTime requestedDate) throws CatalogApiException {
-        return versionForDate(requestedDate).planCancelPolicy(planPhase);
+    public BillingActionPolicy planCancelPolicy(final PlanPhaseSpecifier planPhase,
+                                                final DateTime requestedDate,
+                                                final DateTime subscriptionStartDate) throws CatalogApiException {
+        final StaticCatalog staticCatalog = getStaticCatalog(planPhase, requestedDate, subscriptionStartDate);
+        return staticCatalog.planCancelPolicy(planPhase);
     }
 
     @Override
     public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier from,
-                                                   final PlanSpecifier to, final DateTime requestedDate) throws CatalogApiException {
-        return versionForDate(requestedDate).planChangeAlignment(from, to);
+                                                   final PlanSpecifier to,
+                                                   final DateTime requestedDate,
+                                                   final DateTime subscriptionStartDate) throws CatalogApiException {
+        final StaticCatalog staticCatalog = getStaticCatalog(from, requestedDate, subscriptionStartDate);
+        return staticCatalog.planChangeAlignment(from, to);
     }
 
     @Override
-    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier, final DateTime requestedDate) throws CatalogApiException {
-        return versionForDate(requestedDate).planCreateAlignment(specifier);
+    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier,
+                                                   final DateTime requestedDate,
+                                                   final DateTime subscriptionStartDate) throws CatalogApiException {
+        final StaticCatalog staticCatalog = getStaticCatalog(specifier, requestedDate, subscriptionStartDate);
+        return staticCatalog.planCreateAlignment(specifier);
     }
 
     @Override
-    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase, final DateTime requestedDate) throws CatalogApiException {
-        return versionForDate(requestedDate).billingAlignment(planPhase);
+    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase,
+                                             final DateTime requestedDate,
+                                             final DateTime subscriptionStartDate) throws CatalogApiException {
+        final StaticCatalog staticCatalog = getStaticCatalog(planPhase, requestedDate, subscriptionStartDate);
+        return staticCatalog.billingAlignment(planPhase);
     }
 
     @Override
-    public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate)
+    public PlanChangeResult planChange(final PlanPhaseSpecifier from,
+                                       final PlanSpecifier to,
+                                       final DateTime requestedDate,
+                                       final DateTime subscriptionStartDate)
             throws CatalogApiException {
-        return versionForDate(requestedDate).planChange(from, to);
+        final StaticCatalog staticCatalog = getStaticCatalog(from, requestedDate, subscriptionStartDate);
+        return staticCatalog.planChange(from, to);
     }
 
-    @Override
-    public boolean canCreatePlan(final PlanSpecifier specifier, final DateTime requestedDate)
-            throws CatalogApiException {
-        return versionForDate(requestedDate).canCreatePlan(specifier);
+    // Note that the PlanSpecifier billing period must refer here to the recurring phase one when a plan name isn't specified
+    private StaticCatalog getStaticCatalog(final PlanSpecifier spec, final DateTime requestedDate, final DateTime subscriptionStartDate) throws CatalogApiException {
+        final CatalogPlanEntry entry = findCatalogPlanEntry(new PlanRequestWrapper(spec), requestedDate, subscriptionStartDate);
+        return entry.getStaticCatalog();
     }
 
-    //
-    // VerifiableConfig API
-    //
     @Override
     public void initialize(final VersionedCatalog catalog, final URI sourceURI) {
         //
@@ -428,13 +372,12 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
 
     @Override
     public ValidationErrors validate(final VersionedCatalog catalog, final ValidationErrors errors) {
-
         final Set<Date> effectiveDates = new TreeSet<Date>();
 
         for (final StandaloneCatalog c : versions) {
             if (effectiveDates.contains(c.getEffectiveDate())) {
                 errors.add(new ValidationError(String.format("Catalog effective date '%s' already exists for a previous version", c.getEffectiveDate()),
-                        c.getCatalogURI(), VersionedCatalog.class, ""));
+                                               c.getCatalogURI(), VersionedCatalog.class, ""));
             } else {
                 effectiveDates.add(c.getEffectiveDate());
             }
@@ -507,12 +450,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     }
 
     @Override
-    public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier from,
-                                                final PlanSpecifier to) throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).planChangePolicy(from, to);
-    }
-
-    @Override
     public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to)
             throws CatalogApiException {
         return versionForDate(clock.getUTCNow()).planChange(from, to);
@@ -543,12 +480,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     }
 
     @Override
-    public boolean canCreatePlan(final PlanSpecifier specifier)
-            throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).canCreatePlan(specifier);
-    }
-
-    @Override
     public List<Listing> getAvailableAddOnListings(final String baseProductName, @Nullable final String priceListName) throws CatalogApiException {
         return versionForDate(clock.getUTCNow()).getAvailableAddOnListings(baseProductName, priceListName);
     }
@@ -559,11 +490,6 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     }
 
     @Override
-    public boolean compliesWithLimits(final String phaseName, final String unit, final double value) throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).compliesWithLimits(phaseName, unit, value);
-    }
-
-    @Override
     public void readExternal(final ObjectInput in) throws IOException {
         MapperHolder.mapper().readerForUpdating(this).readValue(new ExternalizableInput(in));
     }
@@ -572,4 +498,51 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     public void writeExternal(final ObjectOutput oo) throws IOException {
         MapperHolder.mapper().writeValue(new ExternalizableOutput(oo), this);
     }
+
+    private static class CatalogPlanEntry {
+
+        private final StaticCatalog staticCatalog;
+        private final Plan plan;
+
+        public CatalogPlanEntry(final StaticCatalog staticCatalog, final Plan plan) {
+            this.staticCatalog = staticCatalog;
+            this.plan = plan;
+        }
+
+        public StaticCatalog getStaticCatalog() {
+            return staticCatalog;
+        }
+
+        public Plan getPlan() {
+            return plan;
+        }
+    }
+
+    private class PlanRequestWrapper {
+
+        private final PlanSpecifier spec;
+        private final PlanPhasePriceOverridesWithCallContext overrides;
+
+        public PlanRequestWrapper(final String planName) {
+            this(new PlanSpecifier(planName));
+        }
+
+        public PlanRequestWrapper(final PlanSpecifier spec) {
+            this(spec, null);
+        }
+
+        public PlanRequestWrapper(final PlanSpecifier spec,
+                                  final PlanPhasePriceOverridesWithCallContext overrides) {
+            this.spec = spec;
+            this.overrides = overrides;
+        }
+
+        public Plan findPlan(final StandaloneCatalog catalog) throws CatalogApiException {
+            return catalog.createOrFindCurrentPlan(spec, overrides);
+        }
+
+        public PlanSpecifier getSpec() {
+            return spec;
+        }
+    }
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
index f5513d6..b3f5bd0 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project 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
@@ -27,19 +27,13 @@ import java.net.URL;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.xml.bind.JAXBException;
-import javax.xml.transform.TransformerException;
-
 import org.joda.time.DateTime;
 import org.killbill.billing.catalog.CatalogTestSuiteNoDB;
 import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
 import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.testng.Assert;
 import org.testng.annotations.Test;
-import org.xml.sax.SAXException;
 
 import com.google.common.io.Files;
 import com.google.common.io.Resources;
@@ -118,14 +112,16 @@ public class TestVersionedCatalogLoader extends CatalogTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testLoad() throws IOException, SAXException, InvalidConfigException, JAXBException, TransformerException, URISyntaxException, CatalogApiException {
+    public void testLoad() throws CatalogApiException {
         final VersionedCatalog c = loader.loadDefaultCatalog(Resources.getResource("versionedCatalog").toString());
-        Assert.assertEquals(c.size(), 3);
+        Assert.assertEquals(c.size(), 4);
         final Iterator<StandaloneCatalog> it = c.iterator();
         DateTime dt = new DateTime("2011-01-01T00:00:00+00:00");
         Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
         dt = new DateTime("2011-02-02T00:00:00+00:00");
         Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
+        dt = new DateTime("2011-02-03T00:00:00+00:00");
+        Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
         dt = new DateTime("2011-03-03T00:00:00+00:00");
         Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
     }
@@ -145,7 +141,7 @@ public class TestVersionedCatalogLoader extends CatalogTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testLoadCatalogFromInsideResourceFolder() throws CatalogApiException, URISyntaxException, IOException {
+    public void testLoadCatalogFromInsideResourceFolder() throws CatalogApiException {
         final VersionedCatalog c = loader.loadDefaultCatalog("com/acme/SpyCarCustom.xml");
         Assert.assertEquals(c.size(), 1);
         final DateTime dt = new DateTime("2015-10-04T00:00:00+00:00");
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
index 1744d0d..5b3f1b2 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project 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:
  *
@@ -17,18 +19,14 @@
 package org.killbill.billing.catalog;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.Date;
 import java.util.Iterator;
-import java.util.LinkedList;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingAlignment;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.CatalogEntity;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanAlignmentChange;
@@ -42,18 +40,10 @@ import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.Unit;
-import org.killbill.billing.catalog.rules.DefaultCaseCancelPolicy;
-import org.killbill.billing.catalog.rules.DefaultCaseChangePlanAlignment;
-import org.killbill.billing.catalog.rules.DefaultCaseChangePlanPolicy;
-import org.killbill.billing.catalog.rules.DefaultCaseCreateAlignment;
 import org.killbill.billing.catalog.rules.DefaultPlanRules;
 
-import com.google.common.collect.ImmutableList;
-
 public class MockCatalog extends StandaloneCatalog implements Catalog {
 
-    private static final String[] PRODUCT_NAMES = new String[]{"TestProduct1", "TestProduct2", "TestProduct3"};
-    private boolean canCreatePlan;
     private PlanChangeResult planChange;
     private BillingAlignment billingAlignment;
     private PlanAlignmentCreate planCreateAlignment;
@@ -70,15 +60,6 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
         setPlanRules(new DefaultPlanRules());
     }
 
-    public void setRules(
-            final DefaultCaseChangePlanPolicy[] caseChangePlanPolicy,
-            final DefaultCaseChangePlanAlignment[] caseChangePlanAlignment,
-            final DefaultCaseCancelPolicy[] caseCancelPolicy,
-            final DefaultCaseCreateAlignment[] caseCreateAlignment
-                        ) {
-
-    }
-
     public void populatePriceLists() {
         final Collection<Plan> plans = getCurrentPlans();
 
@@ -88,7 +69,7 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
         final Plan initialPlan = it.next();
         while (it.hasNext()) {
             final Plan plan = it.next();
-            priceList[i - 1] = new DefaultPriceList(new DefaultPlan[] { (DefaultPlan) plan}, plan.getName() + "-pl");
+            priceList[i - 1] = new DefaultPriceList(new DefaultPlan[]{(DefaultPlan) plan}, plan.getName() + "-pl");
             i++;
         }
 
@@ -96,37 +77,33 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
         setPriceLists(set);
     }
 
-    public String[] getProductNames() {
-        return PRODUCT_NAMES;
-    }
-
     @Override
-    public Date getStandaloneCatalogEffectiveDate(final DateTime dateTime) throws CatalogApiException {
+    public Date getStandaloneCatalogEffectiveDate(final DateTime dateTime) {
         return getEffectiveDate();
     }
 
     @Override
-    public Currency[] getSupportedCurrencies(final DateTime requestedDate) throws CatalogApiException {
+    public Currency[] getSupportedCurrencies(final DateTime requestedDate) {
         return getCurrentSupportedCurrencies();
     }
 
     @Override
-    public Unit[] getUnits(final DateTime requestedDate) throws CatalogApiException {
+    public Unit[] getUnits(final DateTime requestedDate) {
         return getCurrentUnits();
     }
 
     @Override
-    public Collection<Product> getProducts(final DateTime requestedDate) throws CatalogApiException {
+    public Collection<Product> getProducts(final DateTime requestedDate) {
         return getCurrentProducts();
     }
 
     @Override
-    public Collection<Plan> getPlans(final DateTime requestedDate) throws CatalogApiException {
+    public Collection<Plan> getPlans(final DateTime requestedDate) {
         return getCurrentPlans();
     }
 
     @Override
-    public PriceListSet getPriceLists(final DateTime dateTime) throws CatalogApiException {
+    public PriceListSet getPriceLists(final DateTime dateTime) {
         return getPriceLists();
     }
 
@@ -136,7 +113,7 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public Plan createOrFindPlan(final PlanSpecifier spec, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate)
+    public Plan createOrFindPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate)
             throws CatalogApiException {
         return createOrFindCurrentPlan(spec, overrides);
     }
@@ -148,8 +125,8 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public Plan createOrFindPlan(final PlanSpecifier spec, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate,
-                         final DateTime subscriptionStartDate) throws CatalogApiException {
+    public Plan createOrFindPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate,
+                                 final DateTime subscriptionStartDate) throws CatalogApiException {
         return createOrFindCurrentPlan(spec, overrides);
     }
 
@@ -165,62 +142,38 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public PriceList findPriceList(final String name, final DateTime requestedDate) throws CatalogApiException {
-        return findCurrentPricelist(name);
-    }
-
-    @Override
     public PriceList findPriceListForPlan(final String name, final DateTime requestedDate, final DateTime subscriptionStartDate) throws CatalogApiException {
-        return findCurrentPricelist(name);
-    }
-
-    @Override
-    public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate)
-            throws CatalogApiException {
-        return planChangePolicy(from, to);
+        return findCurrentPricelist(findCurrentPlan(name).getPriceListName());
     }
 
     @Override
-    public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate)
-            throws CatalogApiException {
+    public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate, final DateTime subscriptionStartDate) {
         return planChange(from, to);
     }
 
     @Override
-    public BillingActionPolicy planCancelPolicy(final PlanPhaseSpecifier planPhase, final DateTime requestedDate)
+    public BillingActionPolicy planCancelPolicy(final PlanPhaseSpecifier planPhase, final DateTime requestedDate, final DateTime subscriptionStartDate)
             throws CatalogApiException {
         return planCancelPolicy(planPhase);
     }
 
     @Override
-    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier, final DateTime requestedDate)
-            throws CatalogApiException {
+    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier, final DateTime requestedDate, final DateTime subscriptionStartDate) {
         return planCreateAlignment(specifier);
     }
 
     @Override
-    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase, final DateTime requestedDate)
-            throws CatalogApiException {
+    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase, final DateTime requestedDate, final DateTime subscriptionStartDate) {
         return billingAlignment(planPhase);
     }
 
     @Override
-    public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate)
+    public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier from, final PlanSpecifier to, final DateTime requestedDate, final DateTime subscriptionStartDate)
             throws CatalogApiException {
         return planChangeAlignment(from, to);
     }
 
     @Override
-    public boolean canCreatePlan(final PlanSpecifier specifier, final DateTime requestedDate) throws CatalogApiException {
-        return canCreatePlan(specifier);
-    }
-
-    @Override
-    public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier from, final PlanSpecifier to) throws CatalogApiException {
-        return super.planChangePolicy(from, to);
-    }
-
-    @Override
     public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier from, final PlanSpecifier to)
             throws CatalogApiException {
         return super.planChangeAlignment(from, to);
@@ -232,46 +185,24 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier) throws CatalogApiException {
+    public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier specifier) {
         return planCreateAlignment;
     }
 
     @Override
-    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase) throws CatalogApiException {
+    public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhase) {
         return billingAlignment;
     }
 
     @Override
-    public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to) throws CatalogApiException {
+    public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to) {
         return planChange;
     }
 
-    @Override
-    public boolean canCreatePlan(final PlanSpecifier specifier) throws CatalogApiException {
-        return canCreatePlan;
-    }
-
-
-    public DefaultProduct getCurrentProduct(int idx) {
+    public DefaultProduct getCurrentProduct(final int idx) {
         return (DefaultProduct) getCurrentProducts().toArray()[idx];
     }
 
-    private <T extends CatalogEntity> void convertCurrentEntries(final Collection<T> unordered, final T [] result) {
-        // Tests are not so well written and make assumption on how such entries are ordered
-        final LinkedList<T> list = new LinkedList<T>(unordered);
-        Collections.sort(list, new Comparator<T>() {
-            @Override
-            public int compare(final T o1, final T o2) {
-                return o1.getName().compareTo(o2.getName());
-            }
-        });
-        list.toArray(result);
-    }
-
-    public void setCanCreatePlan(final boolean canCreatePlan) {
-        this.canCreatePlan = canCreatePlan;
-    }
-
     public void setPlanChange(final PlanChangeResult planChange) {
         this.planChange = planChange;
     }
@@ -283,5 +214,4 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     public void setPlanCreateAlignment(final PlanAlignmentCreate planCreateAlignment) {
         this.planCreateAlignment = planCreateAlignment;
     }
-
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java b/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
index 9fde075..e4ed959 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
@@ -96,6 +96,7 @@ public class MockPlan extends DefaultPlan {
         setInitialPhases(planPhases);
         setPlansAllowedInBundle(plansAllowedInBundle);
         setRecurringBillingMode(BillingMode.IN_ADVANCE);
+        setPriceListName(DefaultPriceListSet.DEFAULT_PRICELIST_NAME);
 
         finalPhase.setPlan(this);
         for (final DefaultPlanPhase pp : planPhases) {
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
index a6fe002..4bcee55 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project 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
@@ -22,15 +22,29 @@ import java.math.BigDecimal;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanSpecifier;
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
 
+    final DateTime dt0 = new DateTime("2010-01-01T00:00:00+00:00");
+    // WeaponsHireSmall-1.xml
+    final DateTime dt1 = new DateTime("2011-01-01T00:01:00+00:00");
+    // WeaponsHireSmall-2.xml
+    final DateTime dt2 = new DateTime("2011-02-02T00:01:00+00:00");
+    // WeaponsHireSmall-2a.xml
+    final DateTime dt2a = new DateTime("2011-02-03T00:01:00+00:00");
+    // effectiveDateForExistingSubscriptions from the catalogs 2 and 2a
+    final DateTime dt214 = new DateTime("2011-02-14T00:01:00+00:00");
+    // WeaponsHireSmall-3.xml
+    final DateTime dt3 = new DateTime("2011-03-03T00:01:00+00:00");
+
     private VersionedCatalog vc;
 
     @BeforeClass(groups = "fast")
@@ -43,16 +57,9 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
         vc = loader.loadDefaultCatalog("versionedCatalog");
     }
 
-
     @Test(groups = "fast")
     public void testFindPlanWithDates() throws Exception {
-        final DateTime dt0 = new DateTime("2010-01-01T00:00:00+00:00");
-        final DateTime dt1 = new DateTime("2011-01-01T00:01:00+00:00");
-        final DateTime dt2 = new DateTime("2011-02-02T00:01:00+00:00");
-        final DateTime dt214 = new DateTime("2011-02-14T00:01:00+00:00");
-        final DateTime dt3 = new DateTime("2011-03-03T00:01:00+00:00");
-
-        // We find it although the date provided is too early because we default to first catalog version
+        // We find it although the date provided is too early because we default to first catalog version (see also testErrorOnDateTooEarly below)
         final Plan newSubPlan0 = vc.findPlan("pistol-monthly", dt0, dt0);
 
         final Plan newSubPlan1 = vc.findPlan("pistol-monthly", dt1, dt1);
@@ -70,17 +77,66 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
         final Plan exSubPlan2 = vc.findPlan("pistol-monthly", dt2, dt1);
         final Plan exSubPlan214 = vc.findPlan("pistol-monthly", dt214, dt1);
         final Plan exSubPlan3 = vc.findPlan("pistol-monthly", dt3, dt1);
+        // Plan added in subsequent catalog (at dt2)
+        final Plan exSubPlan4 = vc.findPlan("shotgun-quarterly", dt2, dt1);
+        final Plan exSubPlan5 = vc.findPlan("shotgun-quarterly", dt2a, dt1);
+        final Plan exSubPlan6 = vc.findPlan("shotgun-quarterly", dt214, dt1);
+        final Plan exSubPlan7 = vc.findPlan("shotgun-quarterly", dt214, dt214);
 
         Assert.assertEquals(exSubPlan2.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("29.95"));
         Assert.assertEquals(exSubPlan214.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
         Assert.assertEquals(exSubPlan3.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
+        Assert.assertEquals(exSubPlan4.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("249.95"));
+        // Old price
+        Assert.assertEquals(exSubPlan5.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("249.95"));
+        // New price
+        Assert.assertEquals(exSubPlan6.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("259.95"));
+        Assert.assertEquals(exSubPlan7.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("259.95"));
+    }
+
+    // Similar to testFindPlanWithDates, but use the API with PlanSpecifier
+    @Test(groups = "fast")
+    public void testFindPlanWithDatesAndPlanSpecifier() throws Exception {
+        final PlanSpecifier pistolMonthly = new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, "DEFAULT");
+        final PlanSpecifier shotgunQuarterly = new PlanSpecifier("Shotgun", BillingPeriod.QUARTERLY, "DEFAULT");
+
+        // We find it although the date provided is too early because we default to first catalog version (see also testErrorOnDateTooEarly below)
+        final Plan newSubPlan0 = vc.createOrFindPlan(pistolMonthly, null, dt0, dt0);
+
+        final Plan newSubPlan1 = vc.createOrFindPlan(pistolMonthly, null, dt1, dt1);
+        final Plan newSubPlan2 = vc.createOrFindPlan(pistolMonthly, null, dt2, dt2);
+        final Plan newSubPlan214 = vc.createOrFindPlan(pistolMonthly, null, dt214, dt214);
+        final Plan newSubPlan3 = vc.createOrFindPlan(pistolMonthly, null, dt3, dt3);
 
+        Assert.assertEquals(newSubPlan1.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("29.95"));
+        Assert.assertEquals(newSubPlan2.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
+        Assert.assertEquals(newSubPlan214.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
+        Assert.assertEquals(newSubPlan3.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("49.95"));
+
+        // Existing subscription
+
+        final Plan exSubPlan2 = vc.createOrFindPlan(pistolMonthly, null, dt2, dt1);
+        final Plan exSubPlan214 = vc.createOrFindPlan(pistolMonthly, null, dt214, dt1);
+        final Plan exSubPlan3 = vc.createOrFindPlan(pistolMonthly, null, dt3, dt1);
+        // Plan added in subsequent catalog (at dt2)
+        final Plan exSubPlan4 = vc.createOrFindPlan(shotgunQuarterly, null, dt2, dt1);
+        final Plan exSubPlan5 = vc.createOrFindPlan(shotgunQuarterly, null, dt2a, dt1);
+        final Plan exSubPlan6 = vc.createOrFindPlan(shotgunQuarterly, null, dt214, dt1);
+        final Plan exSubPlan7 = vc.createOrFindPlan(shotgunQuarterly, null, dt214, dt214);
+
+        Assert.assertEquals(exSubPlan2.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("29.95"));
+        Assert.assertEquals(exSubPlan214.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
+        Assert.assertEquals(exSubPlan3.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("39.95"));
+        Assert.assertEquals(exSubPlan4.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("249.95"));
+        // Old price
+        Assert.assertEquals(exSubPlan5.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("249.95"));
+        // New price
+        Assert.assertEquals(exSubPlan6.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("259.95"));
+        Assert.assertEquals(exSubPlan7.getAllPhases()[1].getRecurring().getRecurringPrice().getPrice(Currency.USD), new BigDecimal("259.95"));
     }
 
     @Test(groups = "fast")
     public void testErrorOnDateTooEarly() throws CatalogApiException {
-        final DateTime dt0 = new DateTime("1977-01-01T00:00:00+00:00");
-
         // We find it although the date provided is too early because we default to first catalog version
         vc.findPlan("shotgun-monthly", dt0);
 
@@ -88,25 +144,26 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
             // We **don't find it** because date is too early and not part of first catalog version
             vc.findPlan("shotgun-quarterly", dt0);
             Assert.fail("Date is too early an exception should have been thrown");
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             Assert.assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PLAN.getCode());
         }
     }
 
-
     @Test(groups = "fast")
     public void testWithDeletedPlan() throws CatalogApiException {
-
         // We find it because this is version 2 whose effectiveDate is "2011-02-02T00:00:00+00:00"
-        vc.findPlan("shotgun-quarterly", new DateTime("2011-02-02T00:01:00+00:00"));
+        vc.findPlan("shotgun-quarterly", dt2);
 
         try {
             // We **don't find it** because date provided matches version 3 where plan was removed
-            vc.findPlan("shotgun-quarterly", new DateTime("2011-03-03T00:01:00+00:00"));
+            vc.findPlan("shotgun-quarterly", dt3);
             Assert.fail("Plan has been removed");
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             Assert.assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PLAN.getCode());
         }
 
+        // Similar test but for existing subscription: we want to find the plan in the original catalog in this case.
+        // This would be called for instance when computing billing events (dt3 could be a future PHASE event for instance)
+        vc.findPlan("shotgun-quarterly", dt3, dt1);
     }
 }
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index f333572..5f1a214 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
   ~ Copyright 2010-2013 Ning, Inc.
+  ~ Copyright 2014-2018 Groupon, Inc
+  ~ Copyright 2014-2018 The Billing Project, LLC
   ~
-  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ The Billing Project 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:
   ~
@@ -16,7 +18,7 @@
   -->
 
 <catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+         xsi:noNamespaceSchemaLocation="http://docs.killbill.io/latest/catalog.xsd">
 
     <effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
     <catalogName>WeaponsHireSmall</catalogName>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index 3fee3ea..0e11d5b 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
   ~ Copyright 2010-2013 Ning, Inc.
+  ~ Copyright 2014-2018 Groupon, Inc
+  ~ Copyright 2014-2018 The Billing Project, LLC
   ~
-  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ The Billing Project 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:
   ~
@@ -15,8 +17,16 @@
   ~ under the License.
   -->
 
+<!---
+
+Changes compared to WeaponsHireSmall-1.xml:
+  * default change policy IMMEDIATE
+  * pistol-monthly price change
+  * new shotgun-quarterly plan
+
+-->
 <catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+         xsi:noNamespaceSchemaLocation="http://docs.killbill.io/latest/catalog.xsd">
 
     <effectiveDate>2011-02-02T00:00:00+00:00</effectiveDate>
     <catalogName>WeaponsHireSmall</catalogName>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2a.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2a.xml
new file mode 100644
index 0000000..c2ecfd6
--- /dev/null
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2a.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2010-2013 Ning, Inc.
+  ~ Copyright 2014-2018 Groupon, Inc
+  ~ Copyright 2014-2018 The Billing Project, LLC
+  ~
+  ~ The Billing Project 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.
+  -->
+
+<!---
+
+Changes compared to WeaponsHireSmall-2.xml:
+  * shotgun-quarterly price change
+
+-->
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="http://docs.killbill.io/latest/catalog.xsd">
+
+    <effectiveDate>2011-02-03T00:00:00+00:00</effectiveDate>
+    <catalogName>WeaponsHireSmall</catalogName>
+
+    <recurringBillingMode>IN_ADVANCE</recurringBillingMode>
+
+    <currencies>
+        <currency>USD</currency>
+        <currency>EUR</currency>
+        <currency>GBP</currency>
+    </currencies>
+
+    <units>
+        <unit name="targets"/>
+        <unit name="misfires"/>
+        <unit name="shells"/>
+    </units>
+
+    <products>
+        <product name="Pistol">
+            <category>BASE</category>
+        </product>
+        <product name="Shotgun">
+            <category>BASE</category>
+            <limits>
+                <limit>
+                    <unit>shells</unit>
+                    <max>300</max>
+                </limit>
+            </limits>
+        </product>
+        <product name="Laser-Scope">
+            <category>ADD_ON</category>
+        </product>
+        <product name="Extra-Ammo">
+            <category>ADD_ON</category>
+        </product>
+    </products>
+
+    <rules>
+        <changePolicy>
+            <changePolicyCase>
+                <fromBillingPeriod>MONTHLY</fromBillingPeriod>
+                <toProduct>Shotgun</toProduct>
+                <toBillingPeriod>MONTHLY</toBillingPeriod>
+                <policy>END_OF_TERM</policy>
+            </changePolicyCase>
+            <changePolicyCase>
+                <phaseType>TRIAL</phaseType>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+            <changePolicyCase>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+        </changePolicy>
+        <changeAlignment>
+            <changeAlignmentCase>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </changeAlignmentCase>
+        </changeAlignment>
+        <cancelPolicy>
+            <cancelPolicyCase>
+                <policy>IMMEDIATE</policy>
+            </cancelPolicyCase>
+        </cancelPolicy>
+        <createAlignment>
+            <createAlignmentCase>
+                <product>Laser-Scope</product>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </createAlignmentCase>
+            <createAlignmentCase>
+                <alignment>START_OF_BUNDLE</alignment>
+            </createAlignmentCase>
+        </createAlignment>
+    </rules>
+
+    <plans>
+        <plan name="pistol-monthly">
+            <effectiveDateForExistingSubscriptions>2011-02-14T00:00:00+00:00</effectiveDateForExistingSubscriptions>
+
+            <product>Pistol</product>
+            <initialPhases>
+                <phase type="TRIAL">
+                    <duration>
+                        <unit>DAYS</unit>
+                        <number>30</number>
+                    </duration>
+                    <fixed>
+                        <fixedPrice> <!-- empty price implies $0 -->
+                        </fixedPrice>
+                    </fixed>
+                </phase>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <recurring>
+                    <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>39.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>39.95</value>
+                        </price>
+                        <price>
+                            <currency>USD</currency>
+                            <value>39.95</value>
+                        </price>
+                    </recurringPrice>
+                    <!--
+                    <limits>
+                        <limit>
+                            <unit>targets</unit>
+                            <min>3</min>
+                        </limit>
+                        <limit>
+                            <unit>misfires</unit>
+                            <max>20</max>
+                        </limit>
+                    </limits>
+                    -->
+                </recurring>
+            </finalPhase>
+        </plan>
+        <plan name="shotgun-monthly">
+            <product>Shotgun</product>
+            <initialPhases>
+                <phase type="TRIAL">
+                    <duration>
+                        <unit>DAYS</unit>
+                        <number>30</number>
+                    </duration>
+                    <fixed>
+                        <fixedPrice> <!-- empty price implies $0 -->
+                        </fixedPrice>
+                    </fixed>
+                </phase>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                    <number>-1</number>
+                </duration>
+                <recurring>
+                    <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>249.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>149.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>169.95</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
+        <plan name="shotgun-quarterly">
+            <effectiveDateForExistingSubscriptions>2011-02-14T00:00:00+00:00</effectiveDateForExistingSubscriptions>
+
+            <product>Shotgun</product>
+            <initialPhases>
+                <phase type="TRIAL">
+                    <duration>
+                        <unit>DAYS</unit>
+                        <number>30</number>
+                    </duration>
+                    <fixed>
+                        <fixedPrice> <!-- empty price implies $0 -->
+                        </fixedPrice>
+                    </fixed>
+                </phase>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                    <number>-1</number>
+                </duration>
+                <recurring>
+                    <billingPeriod>QUARTERLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>259.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>159.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>179.95</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
+        <plan name="shotgun-annual">
+            <product>Shotgun</product>
+            <initialPhases>
+                <phase type="TRIAL">
+                    <duration>
+                        <unit>DAYS</unit>
+                        <number>30</number>
+                    </duration>
+                    <fixed>
+                        <fixedPrice> <!-- empty price implies $0 -->
+                        </fixedPrice>
+                    </fixed>
+                </phase>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <recurring>
+                    <billingPeriod>ANNUAL</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>2399.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>1499.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>1699.95</value>
+                        </price>
+                    </recurringPrice>
+                    <!--
+                    <limits>
+                        <limit>
+                            <unit>shells</unit>
+                            <max>200</max>
+                        </limit>
+                    </limits>
+                    -->
+                </recurring>
+            </finalPhase>
+        </plan>
+        <plan name="laser-scope-monthly">
+            <product>Laser-Scope</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <recurring>
+
+                    <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>1999.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>1499.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>1999.95</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
+        <plan name="extra-ammo-monthly">
+            <product>Extra-Ammo</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <recurring>
+                    <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>1999.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>1499.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>1999.95</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
+    </plans>
+    <priceLists>
+        <defaultPriceList name="DEFAULT">
+            <plans>
+                <plan>pistol-monthly</plan>
+                <plan>shotgun-monthly</plan>
+                <plan>shotgun-quarterly</plan>
+                <plan>shotgun-annual</plan>
+                <plan>laser-scope-monthly</plan>
+                <plan>extra-ammo-monthly</plan>
+            </plans>
+        </defaultPriceList>
+    </priceLists>
+</catalog>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index eb21229..779a440 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
   ~ Copyright 2010-2013 Ning, Inc.
+  ~ Copyright 2014-2018 Groupon, Inc
+  ~ Copyright 2014-2018 The Billing Project, LLC
   ~
-  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ The Billing Project 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:
   ~
@@ -15,8 +17,15 @@
   ~ under the License.
   -->
 
+<!---
+
+Changes compared to WeaponsHireSmall-2a.xml:
+  * pistol-monthly price change
+  * shotgun-quarterly plan retired
+
+-->
 <catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+         xsi:noNamespaceSchemaLocation="http://docs.killbill.io/latest/catalog.xsd">
 
     <effectiveDate>2011-03-03T00:00:00+00:00</effectiveDate>
     <catalogName>WeaponsHireSmall</catalogName>

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

diff --git a/currency/pom.xml b/currency/pom.xml
index 7a97157..623f640 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-currency</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 31beb3d..c8645c9 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index 637ad39..6b1991b 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -36,14 +36,11 @@ import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogInternalApi;
 import org.killbill.billing.catalog.api.PhaseType;
-import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.AccountEventsStreams;
 import org.killbill.billing.entitlement.EventsStream;
@@ -423,36 +420,17 @@ public class EventsStreamBuilder {
     }
 
     private PlanPhaseSpecifier createPlanPhaseSpecifier(final SubscriptionBase subscription) {
-
-        final String lastActiveProductName;
-        final BillingPeriod billingPeriod;
-        final ProductCategory productCategory;
-        final String priceListName;
+        final String planName;
         final PhaseType phaseType;
-
         if (subscription.getState() == EntitlementState.PENDING) {
             final SubscriptionBaseTransition transition = subscription.getPendingTransition();
-            final Product pendingProduct = transition.getNextPlan().getProduct();
-            lastActiveProductName = pendingProduct.getName();
-            productCategory = pendingProduct.getCategory();
-            final PlanPhase pendingPlanPhase = transition.getNextPhase();
-            billingPeriod = pendingPlanPhase.getRecurring() != null ? pendingPlanPhase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
-            priceListName = transition.getNextPriceList().getName();
+            planName = transition.getNextPlan().getName();
             phaseType = transition.getNextPhase().getPhaseType();
         } else {
-            final Product lastActiveProduct = subscription.getLastActiveProduct();
-            lastActiveProductName = lastActiveProduct.getName();
-            productCategory = lastActiveProduct.getCategory();
-            final PlanPhase lastActivePlanPhase = subscription.getLastActivePhase();
-            billingPeriod = lastActivePlanPhase.getRecurring() != null ? lastActivePlanPhase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
-            priceListName = subscription.getLastActivePlan().getPriceListName();
+            planName = subscription.getLastActivePlan().getName();
             phaseType = subscription.getLastActivePhase().getPhaseType();
         }
-        return new PlanPhaseSpecifier(lastActiveProductName,
-                                      billingPeriod,
-                                      priceListName,
-                                      phaseType);
-
+        return new PlanPhaseSpecifier(planName, phaseType);
     }
 
     private Catalog getCatalog(final InternalTenantContext internalTenantContext) throws EntitlementApiException {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
index 3039f4c..28e957a 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
@@ -248,7 +248,7 @@ public abstract class EntitlementLoggingHelper {
             }
             if (spec.getPriceListName() != null) {
                 logLine.append(", priceList='")
-                       .append(spec.getBillingPeriod())
+                       .append(spec.getPriceListName())
                        .append("'");
             }
             logPlanPhasePriceOverrides(logLine, overrides);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingChecker.java b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingChecker.java
index e8ac66b..193f506 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingChecker.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingChecker.java
@@ -47,6 +47,10 @@ public class TestBlockingChecker extends EntitlementTestSuiteNoDB {
 
     @BeforeMethod(groups = "fast")
     public void beforeMethod() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
+
         super.beforeMethod();
         final UUID accountId = UUID.randomUUID();
         account = Mockito.mock(Account.class);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
index 1fae808..7c5af2e 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
@@ -48,6 +48,9 @@ public class TestDefaultBlockingStateDao extends EntitlementTestSuiteWithEmbedde
 
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
         account = createAccount(getAccountData(7));
     }
 
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index c2b31fd..43974f9 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -65,6 +65,9 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
 
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
         clock.setDay(initialDate);
         final Account account = createAccount(getAccountData(7));
 

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

diff --git a/invoice/pom.xml b/invoice/pom.xml
index fa34ea0..8d13d6f 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 23ce2f9..3485682 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -207,7 +207,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
         return getInvoiceInternal(invoiceId, context);
     }
 
-    private DefaultInvoice getInvoiceInternal(final UUID invoiceId, final TenantContext context) throws InvoiceApiException  {
+    private DefaultInvoice getInvoiceInternal(final UUID invoiceId, final TenantContext context) throws InvoiceApiException {
         final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(invoiceId, ObjectType.INVOICE, context);
         return new DefaultInvoice(dao.getById(invoiceId, internalTenantContext), getCatalogSafelyForPrettyNames(internalTenantContext));
     }
@@ -281,7 +281,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
     @Override
     public List<InvoiceItem> insertExternalCharges(final UUID accountId, final LocalDate effectiveDate, final Iterable<InvoiceItem> charges, final boolean autoCommit, final CallContext context) throws InvoiceApiException {
         for (final InvoiceItem charge : charges) {
-            if (charge.getAmount() == null || charge.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
+            if (charge.getAmount() == null || charge.getAmount().compareTo(BigDecimal.ZERO) < 0) {
                 throw new InvoiceApiException(ErrorCode.EXTERNAL_CHARGE_AMOUNT_INVALID, charge.getAmount());
             }
         }
@@ -606,14 +606,17 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
 
     }
 
+
     @Override
     public List<InvoiceItem> getInvoiceItemsByParentInvoice(final UUID parentInvoiceId, final TenantContext context) throws InvoiceApiException {
         final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(parentInvoiceId, ObjectType.INVOICE, context);
+
+        final Catalog catalog  = getCatalogSafelyForPrettyNames(internalTenantContext);
         return ImmutableList.copyOf(Collections2.transform(dao.getInvoiceItemsByParentInvoice(parentInvoiceId, internalTenantContext),
                                                            new Function<InvoiceItemModelDao, InvoiceItem>() {
                                                                @Override
                                                                public InvoiceItem apply(final InvoiceItemModelDao input) {
-                                                                   return InvoiceItemFactory.fromModelDao(input);
+                                                                   return InvoiceItemFactory.fromModelDaoWithCatalog(input, catalog);
                                                                }
                                                            }));
     }
@@ -643,7 +646,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
     private void canInvoiceBeVoided(final Invoice invoice) throws InvoiceApiException {
         final List<InvoicePayment> invoicePayments = invoice.getPayments();
         final BigDecimal amountPaid = InvoiceCalculatorUtils.computeInvoiceAmountPaid(invoice.getCurrency(), invoicePayments)
-                .add(InvoiceCalculatorUtils.computeInvoiceAmountRefunded(invoice.getCurrency(), invoicePayments));
+                                                            .add(InvoiceCalculatorUtils.computeInvoiceAmountRefunded(invoice.getCurrency(), invoicePayments));
 
         if (amountPaid.compareTo(BigDecimal.ZERO) != 0) {
             throw new InvoiceApiException(ErrorCode.CAN_NOT_VOID_INVOICE_THAT_IS_PAID, invoice.getId().toString());

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

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index de0d67a..f5a8c19 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/.DS_Store b/jaxrs/src/main/java/org/killbill/billing/jaxrs/.DS_Store
new file mode 100644
index 0000000..4d24152
Binary files /dev/null and b/jaxrs/src/main/java/org/killbill/billing/jaxrs/.DS_Store differ
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountEmailJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountEmailJson.java
index ca1afdb..3db9d6d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountEmailJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountEmailJson.java
@@ -27,7 +27,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 
-@ApiModel(value="AccountEmail")
+@ApiModel(value="AccountEmail", parent = JsonBase.class)
 public class AccountEmailJson extends JsonBase {
 
     private final UUID accountId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
index 8f55507..f019a15 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
@@ -38,7 +38,7 @@ import com.google.common.base.Strings;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Account")
+@ApiModel(value="Account", parent = JsonBase.class)
 public class AccountJson extends JsonBase {
 
     private final UUID accountId;
@@ -49,7 +49,7 @@ public class AccountJson extends JsonBase {
     private final Integer firstNameLength;
     private final String email;
     private final Integer billCycleDayLocal;
-    private final String currency;
+    private final Currency currency;
     private final UUID parentAccountId;
     private final Boolean isPaymentDelegatedToParent;
     private final UUID paymentMethodId;
@@ -78,7 +78,7 @@ public class AccountJson extends JsonBase {
         this.firstNameLength = account.getFirstNameLength();
         this.email = account.getEmail();
         this.billCycleDayLocal = account.getBillCycleDayLocal();
-        this.currency = account.getCurrency() != null ? account.getCurrency().toString() : null;
+        this.currency = account.getCurrency();
         this.parentAccountId = account.getParentAccountId();
         this.isPaymentDelegatedToParent = account.isPaymentDelegatedToParent();
         this.paymentMethodId = account.getPaymentMethodId();
@@ -105,7 +105,7 @@ public class AccountJson extends JsonBase {
                        @JsonProperty("externalKey") final String externalKey,
                        @JsonProperty("email") final String email,
                        @JsonProperty("billCycleDayLocal") final Integer billCycleDayLocal,
-                       @JsonProperty("currency") final String currency,
+                       @JsonProperty("currency") final Currency currency,
                        @JsonProperty("parentAccountId") final UUID parentAccountId,
                        @JsonProperty("isPaymentDelegatedToParent") final Boolean isPaymentDelegatedToParent,
                        @JsonProperty("paymentMethodId") final UUID paymentMethodId,
@@ -235,11 +235,7 @@ public class AccountJson extends JsonBase {
 
             @Override
             public Currency getCurrency() {
-                if (Strings.emptyToNull(currency) == null) {
-                    return null;
-                } else {
-                    return Currency.valueOf(currency);
-                }
+                return currency;
             }
 
             @Override
@@ -349,7 +345,7 @@ public class AccountJson extends JsonBase {
         return billCycleDayLocal;
     }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
index 2dd9324..7643502 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
@@ -163,19 +163,19 @@ public class BillingExceptionJson {
         private final String fileName;
         private final Integer lineNumber;
         private final String methodName;
-        private final Boolean nativeMethod;
+        private final Boolean isNativeMethod;
 
         @JsonCreator
         public StackTraceElementJson(@JsonProperty("className") final String className,
                                      @JsonProperty("fileName") final String fileName,
                                      @JsonProperty("lineNumber") final Integer lineNumber,
                                      @JsonProperty("methodName") final String methodName,
-                                     @JsonProperty("nativeMethod") final Boolean nativeMethod) {
+                                     @JsonProperty("isNativeMethod") final Boolean isNativeMethod) {
             this.className = className;
             this.fileName = fileName;
             this.lineNumber = lineNumber;
             this.methodName = methodName;
-            this.nativeMethod = nativeMethod;
+            this.isNativeMethod = isNativeMethod;
         }
 
         public String getClassName() {
@@ -194,8 +194,9 @@ public class BillingExceptionJson {
             return methodName;
         }
 
-        public Boolean getNativeMethod() {
-            return nativeMethod;
+        @JsonProperty("isNativeMethod")
+        public Boolean isNativeMethod() {
+            return isNativeMethod;
         }
 
         @Override
@@ -205,7 +206,7 @@ public class BillingExceptionJson {
             sb.append(", fileName='").append(fileName).append('\'');
             sb.append(", lineNumber=").append(lineNumber);
             sb.append(", methodName='").append(methodName).append('\'');
-            sb.append(", nativeMethod=").append(nativeMethod);
+            sb.append(", isNativeMethod=").append(isNativeMethod);
             sb.append('}');
             return sb.toString();
         }
@@ -233,7 +234,7 @@ public class BillingExceptionJson {
             if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) {
                 return false;
             }
-            if (nativeMethod != null ? !nativeMethod.equals(that.nativeMethod) : that.nativeMethod != null) {
+            if (isNativeMethod != null ? !isNativeMethod.equals(that.isNativeMethod) : that.isNativeMethod != null) {
                 return false;
             }
 
@@ -246,7 +247,7 @@ public class BillingExceptionJson {
             result = 31 * result + (fileName != null ? fileName.hashCode() : 0);
             result = 31 * result + (lineNumber != null ? lineNumber.hashCode() : 0);
             result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
-            result = 31 * result + (nativeMethod != null ? nativeMethod.hashCode() : 0);
+            result = 31 * result + (isNativeMethod != null ? isNativeMethod.hashCode() : 0);
             return result;
         }
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockingStateJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockingStateJson.java
index 1482cf2..bafc4bc 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockingStateJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockingStateJson.java
@@ -23,7 +23,6 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.LocalDate;
 import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.entitlement.api.BlockingStateType;
 import org.killbill.billing.util.audit.AccountAuditLogs;
@@ -31,17 +30,16 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="BlockingState")
+@ApiModel(value="BlockingState", parent = JsonBase.class)
 public class BlockingStateJson extends JsonBase {
 
     private final UUID blockedId;
     private final String stateName;
     private final String service;
-    private final Boolean blockChange;
-    private final Boolean blockEntitlement;
-    private final Boolean blockBilling;
+    private final Boolean isBlockChange;
+    private final Boolean isBlockEntitlement;
+    private final Boolean isBlockBilling;
     private final DateTime effectiveDate;
     private final BlockingStateType type;
 
@@ -49,9 +47,9 @@ public class BlockingStateJson extends JsonBase {
     public BlockingStateJson(@JsonProperty("blockedId") final UUID blockedId,
                              @JsonProperty("stateName") final String stateName,
                              @JsonProperty("service") final String service,
-                             @JsonProperty("blockChange") final Boolean blockChange,
-                             @JsonProperty("blockEntitlement") final Boolean blockEntitlement,
-                             @JsonProperty("blockBilling") final Boolean blockBilling,
+                             @JsonProperty("isBlockChange") final Boolean isBlockChange,
+                             @JsonProperty("isBlockEntitlement") final Boolean isBlockEntitlement,
+                             @JsonProperty("isBlockBilling") final Boolean isBlockBilling,
                              @JsonProperty("effectiveDate") final DateTime effectiveDate,
                              @JsonProperty("type") final BlockingStateType type,
                              @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
@@ -59,9 +57,9 @@ public class BlockingStateJson extends JsonBase {
         this.blockedId = blockedId;
         this.stateName = stateName;
         this.service = service;
-        this.blockChange = blockChange;
-        this.blockEntitlement = blockEntitlement;
-        this.blockBilling = blockBilling;
+        this.isBlockChange = isBlockChange;
+        this.isBlockEntitlement = isBlockEntitlement;
+        this.isBlockBilling = isBlockBilling;
         this.effectiveDate = effectiveDate;
         this.type = type;
     }
@@ -91,16 +89,19 @@ public class BlockingStateJson extends JsonBase {
         return service;
     }
 
+    @JsonProperty("isBlockChange")
     public Boolean isBlockChange() {
-        return blockChange;
+        return isBlockChange;
     }
 
+    @JsonProperty("isBlockEntitlement")
     public Boolean isBlockEntitlement() {
-        return blockEntitlement;
+        return isBlockEntitlement;
     }
 
+    @JsonProperty("isBlockBilling")
     public Boolean isBlockBilling() {
-        return blockBilling;
+        return isBlockBilling;
     }
 
     public DateTime getEffectiveDate() {
@@ -122,13 +123,13 @@ public class BlockingStateJson extends JsonBase {
 
         final BlockingStateJson that = (BlockingStateJson) o;
 
-        if (blockChange != that.blockChange) {
+        if (isBlockChange != that.isBlockChange) {
             return false;
         }
-        if (blockEntitlement != that.blockEntitlement) {
+        if (isBlockEntitlement != that.isBlockEntitlement) {
             return false;
         }
-        if (blockBilling != that.blockBilling) {
+        if (isBlockBilling != that.isBlockBilling) {
             return false;
         }
         if (blockedId != null ? !blockedId.equals(that.blockedId) : that.blockedId != null) {
@@ -152,9 +153,9 @@ public class BlockingStateJson extends JsonBase {
         int result = blockedId != null ? blockedId.hashCode() : 0;
         result = 31 * result + (stateName != null ? stateName.hashCode() : 0);
         result = 31 * result + (service != null ? service.hashCode() : 0);
-        result = 31 * result + (blockChange ? 1 : 0);
-        result = 31 * result + (blockEntitlement ? 1 : 0);
-        result = 31 * result + (blockBilling ? 1 : 0);
+        result = 31 * result + (isBlockChange ? 1 : 0);
+        result = 31 * result + (isBlockEntitlement ? 1 : 0);
+        result = 31 * result + (isBlockBilling ? 1 : 0);
         result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
         result = 31 * result + (type != null ? type.hashCode() : 0);
         return result;
@@ -166,9 +167,9 @@ public class BlockingStateJson extends JsonBase {
                "blockedId='" + blockedId + '\'' +
                ", stateName='" + stateName + '\'' +
                ", service='" + service + '\'' +
-               ", blockChange=" + blockChange +
-               ", blockEntitlement=" + blockEntitlement +
-               ", blockBilling=" + blockBilling +
+               ", isBlockChange=" + isBlockChange +
+               ", isBlockEntitlement=" + isBlockEntitlement +
+               ", isBlockBilling=" + isBlockBilling +
                ", effectiveDate=" + effectiveDate +
                ", type=" + type +
                '}';
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleJson.java
index 78927d3..6438610 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleJson.java
@@ -35,7 +35,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Bundle")
+@ApiModel(value="Bundle", parent = JsonBase.class)
 public class BundleJson extends JsonBase {
 
     @ApiModelProperty(required = true)
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleTimelineJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleTimelineJson.java
index 765096c..fec6601 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleTimelineJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BundleTimelineJson.java
@@ -32,7 +32,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="BundleTimeline")
+@ApiModel(value="BundleTimeline", parent = JsonBase.class)
 public class BundleTimelineJson extends JsonBase {
 
     private final UUID accountId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
index 5a93bc8..1cb6d7b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
@@ -128,7 +128,7 @@ public class CatalogJson {
         Price[] prices = (internationalPrice != null) ? internationalPrice.getPrices() : null;
         if (prices != null && prices.length > 0) {
             for (int i=0; i < prices.length; i++) {
-                pricesJson.add(new PriceJson(prices[i].getCurrency().name(),
+                pricesJson.add(new PriceJson(prices[i].getCurrency(),
                                              prices[i].getValue()));
             }
         }
@@ -932,21 +932,21 @@ public class CatalogJson {
     @ApiModel(value="Price")
     public static class PriceJson {
 
-        private final String currency;
+        private final Currency currency;
         private final BigDecimal value;
 
         @JsonCreator
-        public PriceJson(@JsonProperty("currency") final String currency,
+        public PriceJson(@JsonProperty("currency") final Currency currency,
                          @JsonProperty("value") final BigDecimal value) {
             this.currency = currency;
             this.value = value;
         }
 
         public PriceJson(final Price price) throws CurrencyValueNull {
-            this(price.getCurrency().toString(), price.getValue());
+            this(price.getCurrency(), price.getValue());
         }
 
-        public String getCurrency() {
+        public Currency getCurrency() {
             return currency;
         }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboHostedPaymentPageJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboHostedPaymentPageJson.java
index 0ae0281..490da97 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboHostedPaymentPageJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboHostedPaymentPageJson.java
@@ -23,11 +23,14 @@ import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 
 @ApiModel(value="ComboHostedPaymentPage")
 public class ComboHostedPaymentPageJson extends ComboPaymentJson {
 
+    //@ApiModelProperty(name = required = true)
     private final HostedPaymentPageFieldsJson hostedPaymentPageFields;
 
     @JsonCreator
@@ -40,7 +43,7 @@ public class ComboHostedPaymentPageJson extends ComboPaymentJson {
         this.hostedPaymentPageFields = hostedPaymentPageFields;
     }
 
-    public HostedPaymentPageFieldsJson getHostedPaymentPageFieldsJson() {
+    public HostedPaymentPageFieldsJson getHostedPaymentPageFields() {
         return hostedPaymentPageFields;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentJson.java
index 9828010..f57f8fa 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentJson.java
@@ -25,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 
-@ApiModel(value="ComboPayment")
+@ApiModel(value="ComboPayment", parent = JsonBase.class)
 public abstract class ComboPaymentJson extends JsonBase {
 
     private final AccountJson account;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java
index f7b7b4d..832d1ae 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java
@@ -21,11 +21,14 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
+import org.killbill.billing.payment.api.TransactionType;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 
-@ApiModel(value="ComboPaymentTransaction")
+@ApiModel(value="ComboPaymentTransaction", parent = ComboPaymentJson.class)
 public class ComboPaymentTransactionJson extends ComboPaymentJson {
 
     private final PaymentTransactionJson transaction;
@@ -47,11 +50,11 @@ public class ComboPaymentTransactionJson extends ComboPaymentJson {
         return transaction;
     }
 
-    public String getTransactionType() {
+    @JsonIgnore
+    public TransactionType getTransactionType() {
         if (transaction != null) {
             return transaction.getTransactionType();
         }
-
         return null;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CreditJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CreditJson.java
index ee41c5d..c826fc8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CreditJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CreditJson.java
@@ -25,6 +25,7 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.util.audit.AuditLog;
@@ -34,9 +35,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value = "Credit")
+@ApiModel(value="Credit", parent = JsonBase.class)
 public class CreditJson extends JsonBase {
 
+    private final UUID creditId;
     @ApiModelProperty(required = true)
     private final BigDecimal creditAmount;
     private final UUID invoiceId;
@@ -45,12 +47,13 @@ public class CreditJson extends JsonBase {
     @ApiModelProperty(required = true)
     private final UUID accountId;
     private final String description;
+    private final Currency currency;
     private final String itemDetails;
-    private final String currency;
 
     @JsonCreator
-    public CreditJson(@JsonProperty("creditAmount") final BigDecimal creditAmount,
-                      @JsonProperty("currency") final String currency,
+    public CreditJson(@JsonProperty("creditId") final UUID creditId,
+                      @JsonProperty("creditAmount") final BigDecimal creditAmount,
+                      @JsonProperty("currency") final Currency currency,
                       @JsonProperty("invoiceId") final UUID invoiceId,
                       @JsonProperty("invoiceNumber") final String invoiceNumber,
                       @JsonProperty("effectiveDate") final LocalDate effectiveDate,
@@ -59,6 +62,7 @@ public class CreditJson extends JsonBase {
                       @JsonProperty("itemDetails") final String itemDetails,
                       @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
+        this.creditId = creditId;
         this.creditAmount = creditAmount;
         this.currency = currency;
         this.invoiceId = invoiceId;
@@ -71,9 +75,10 @@ public class CreditJson extends JsonBase {
 
     public CreditJson(final Invoice invoice, final InvoiceItem credit, final List<AuditLog> auditLogs) {
         super(toAuditLogJson(auditLogs));
+        this.creditId = credit.getId();
         this.accountId = credit.getAccountId();
         this.creditAmount = credit.getAmount();
-        this.currency = credit.getCurrency().name();
+        this.currency = credit.getCurrency();
         this.invoiceId = credit.getInvoiceId();
         this.invoiceNumber = invoice.getInvoiceNumber().toString();
         this.effectiveDate = credit.getStartDate();
@@ -109,19 +114,24 @@ public class CreditJson extends JsonBase {
         return description;
     }
 
+    public Currency getCurrency() {
+        return currency;
+    }
+
     public String getItemDetails() {
         return itemDetails;
     }
 
-    public String getCurrency() {
-        return currency;
+    public UUID getCreditId() {
+        return creditId;
     }
 
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("CreditJson");
-        sb.append("{creditAmount=").append(creditAmount);
+        sb.append("{creditId=").append(creditId);
+        sb.append(", creditAmount=").append(creditAmount);
         sb.append(", currency=").append(currency);
         sb.append(", invoiceId=").append(invoiceId);
         sb.append(", invoiceNumber='").append(invoiceNumber).append('\'');
@@ -144,6 +154,9 @@ public class CreditJson extends JsonBase {
 
         final CreditJson that = (CreditJson) o;
 
+        if (creditId != null ? !creditId.equals(that.creditId) : that.creditId != null) {
+            return false;
+        }
         if (!((creditAmount == null && that.creditAmount == null) ||
               (creditAmount != null && that.creditAmount != null && creditAmount.compareTo(that.creditAmount) == 0))) {
             return false;
@@ -174,6 +187,7 @@ public class CreditJson extends JsonBase {
     @Override
     public int hashCode() {
         int result = creditAmount != null ? creditAmount.hashCode() : 0;
+        result = 31 * result + (creditId != null ? creditId.hashCode() : 0);
         result = 31 * result + (currency != null ? currency.hashCode() : 0);
         result = 31 * result + (invoiceId != null ? invoiceId.hashCode() : 0);
         result = 31 * result + (description != null ? description.hashCode() : 0);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CustomFieldJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CustomFieldJson.java
index 6695075..825e09e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CustomFieldJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CustomFieldJson.java
@@ -30,7 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="CustomField")
+@ApiModel(value="CustomField", parent = JsonBase.class)
 public class CustomFieldJson extends JsonBase {
 
     private final UUID customFieldId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/GatewayNotificationJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/GatewayNotificationJson.java
index 69d093a..95342cd 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/GatewayNotificationJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/GatewayNotificationJson.java
@@ -32,7 +32,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="GatewayNotification")
+@ApiModel(value="GatewayNotification", parent = JsonBase.class)
 public class GatewayNotificationJson extends JsonBase {
 
     private final UUID kbPaymentId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageBillingAddressJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageBillingAddressJson.java
index 59bcdb4..26e11ff 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageBillingAddressJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageBillingAddressJson.java
@@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 
-@ApiModel(value="HostedPaymentPageBillingAddress")
+@ApiModel(value="HostedPaymentPageBillingAddress", parent = JsonBase.class)
 public class HostedPaymentPageBillingAddressJson extends JsonBase {
 
     private final String city;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageCustomerJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageCustomerJson.java
index 6631cac..14cb3dc 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageCustomerJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageCustomerJson.java
@@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 
-@ApiModel(value="HostedPaymentPageCustomer")
+@ApiModel(value="HostedPaymentPageCustomer", parent = JsonBase.class)
 public class HostedPaymentPageCustomerJson extends JsonBase {
 
     private final String firstName;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFieldsJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFieldsJson.java
index 7f5b638..fedba4c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFieldsJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFieldsJson.java
@@ -24,16 +24,17 @@ import io.swagger.annotations.ApiModel;
 
 
 @ApiModel(value="HostedPaymentPageFields")
-public class HostedPaymentPageFieldsJson extends JsonBase {
+public class HostedPaymentPageFieldsJson  {
 
     private final List<PluginPropertyJson> formFields;
 
+
     @JsonCreator
     public HostedPaymentPageFieldsJson(@JsonProperty("formFields") final List<PluginPropertyJson> formFields) {
         this.formFields = formFields;
     }
 
-    public List<PluginPropertyJson> getCustomFields() {
+    public List<PluginPropertyJson> getFormFields() {
         return formFields;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFormDescriptorJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFormDescriptorJson.java
index dc7134e..23e94a7 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFormDescriptorJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/HostedPaymentPageFormDescriptorJson.java
@@ -27,7 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="HostedPaymentPageFormDescriptor")
+@ApiModel(value="HostedPaymentPageFormDescriptor", parent = JsonBase.class)
 public class HostedPaymentPageFormDescriptorJson extends JsonBase {
 
     private final UUID kbAccountId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
index 42493da..7b21259 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
@@ -23,6 +23,12 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingActionPolicy;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PhaseType;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
+import org.killbill.billing.invoice.api.DryRunType;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -31,31 +37,31 @@ import io.swagger.annotations.ApiModel;
 @ApiModel(value="InvoiceDryRun")
 public class InvoiceDryRunJson {
 
-    private final String dryRunType;
-    private final String dryRunAction;
-    private final String phaseType;
+    private final DryRunType dryRunType;
+    private final SubscriptionEventType dryRunAction;
+    private final PhaseType phaseType;
     private final String productName;
-    private final String productCategory;
-    private final String billingPeriod;
+    private final ProductCategory productCategory;
+    private final BillingPeriod billingPeriod;
     private final String priceListName;
     private final LocalDate effectiveDate;
     private final UUID subscriptionId;
     private final UUID bundleId;
-    private final String billingPolicy;
+    private final BillingActionPolicy billingPolicy;
     private final List<PhasePriceOverrideJson> priceOverrides;
 
     @JsonCreator
-    public InvoiceDryRunJson(@JsonProperty("dryRunType") @Nullable final String dryRunType,
-                             @JsonProperty("dryRunAction") @Nullable final String dryRunAction,
-                             @JsonProperty("phaseType") @Nullable final String phaseType,
+    public InvoiceDryRunJson(@JsonProperty("dryRunType") @Nullable final DryRunType dryRunType,
+                             @JsonProperty("dryRunAction") @Nullable final SubscriptionEventType dryRunAction,
+                             @JsonProperty("phaseType") @Nullable final PhaseType phaseType,
                              @JsonProperty("productName") @Nullable final String productName,
-                             @JsonProperty("productCategory") @Nullable final String productCategory,
-                             @JsonProperty("billingPeriod") @Nullable final String billingPeriod,
+                             @JsonProperty("productCategory") @Nullable final ProductCategory productCategory,
+                             @JsonProperty("billingPeriod") @Nullable final BillingPeriod billingPeriod,
                              @JsonProperty("priceListName") @Nullable final String priceListName,
                              @JsonProperty("subscriptionId") @Nullable final UUID subscriptionId,
                              @JsonProperty("bundleId") @Nullable final UUID bundleId,
                              @JsonProperty("effectiveDate") @Nullable final LocalDate effectiveDate,
-                             @JsonProperty("billingPolicy") @Nullable final String billingPolicy,
+                             @JsonProperty("billingPolicy") @Nullable final BillingActionPolicy billingPolicy,
                              @JsonProperty("priceOverrides") @Nullable final List<PhasePriceOverrideJson> priceOverrides) {
         this.dryRunType = dryRunType;
         this.dryRunAction = dryRunAction;
@@ -71,15 +77,15 @@ public class InvoiceDryRunJson {
         this.priceOverrides = priceOverrides;
     }
 
-    public String getDryRunType() {
+    public DryRunType getDryRunType() {
         return dryRunType;
     }
 
-    public String getDryRunAction() {
+    public SubscriptionEventType getDryRunAction() {
         return dryRunAction;
     }
 
-    public String getPhaseType() {
+    public PhaseType getPhaseType() {
         return phaseType;
     }
 
@@ -87,11 +93,11 @@ public class InvoiceDryRunJson {
         return productName;
     }
 
-    public String getProductCategory() {
+    public ProductCategory getProductCategory() {
         return productCategory;
     }
 
-    public String getBillingPeriod() {
+    public BillingPeriod getBillingPeriod() {
         return billingPeriod;
     }
 
@@ -111,7 +117,7 @@ public class InvoiceDryRunJson {
         return bundleId;
     }
 
-    public String getBillingPolicy() {
+    public BillingActionPolicy getBillingPolicy() {
         return billingPolicy;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceEmailJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceEmailJson.java
index 9dee36c..df005b6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceEmailJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceEmailJson.java
@@ -24,7 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="InvoiceEmail")
+@ApiModel(value="InvoiceEmail", parent = JsonBase.class)
 public class InvoiceEmailJson extends JsonBase {
 
     private final UUID accountId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
index 6e33670..e43ce7d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
@@ -37,7 +37,7 @@ import com.google.common.collect.ImmutableList;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="InvoiceItem")
+@ApiModel(value="InvoiceItem", parent = JsonBase.class)
 public class InvoiceItemJson extends JsonBase {
 
     @ApiModelProperty( required = true)
@@ -57,13 +57,13 @@ public class InvoiceItemJson extends JsonBase {
     private final String prettyPlanName;
     private final String prettyPhaseName;
     private final String prettyUsageName;
-    private final String itemType;
+    private final InvoiceItemType itemType;
     private final String description;
     private final LocalDate startDate;
     private final LocalDate endDate;
     private final BigDecimal amount;
     private final BigDecimal rate;
-    private final String currency;
+    private final Currency currency;
     private final Integer quantity;
     private final String itemDetails;
     private List<InvoiceItemJson> childItems;
@@ -84,13 +84,13 @@ public class InvoiceItemJson extends JsonBase {
                            @JsonProperty("prettyPlanName") final String prettyPlanName,
                            @JsonProperty("prettyPhaseName") final String prettyPhaseName,
                            @JsonProperty("prettyUsageName") final String prettyUsageName,
-                           @JsonProperty("itemType") final String itemType,
+                           @JsonProperty("itemType") final InvoiceItemType itemType,
                            @JsonProperty("description") final String description,
                            @JsonProperty("startDate") final LocalDate startDate,
                            @JsonProperty("endDate") final LocalDate endDate,
                            @JsonProperty("amount") final BigDecimal amount,
                            @JsonProperty("rate") final  BigDecimal rate,
-                           @JsonProperty("currency") final String currency,
+                           @JsonProperty("currency") final Currency currency,
                            @JsonProperty("quantity") final Integer quantity,
                            @JsonProperty("itemDetails") final String itemDetails,
                            @JsonProperty("childItems") final List<InvoiceItemJson> childItems,
@@ -128,9 +128,9 @@ public class InvoiceItemJson extends JsonBase {
              item.getAccountId(), item.getChildAccountId(), item.getBundleId(), item.getSubscriptionId(),
              item.getProductName(), item.getPlanName(), item.getPhaseName(), item.getUsageName(),
              item.getPrettyProductName(), item.getPrettyPlanName(), item.getPrettyPhaseName(), item.getPrettyUsageName(),
-             item.getInvoiceItemType().toString(),
+             item.getInvoiceItemType(),
              item.getDescription(), item.getStartDate(), item.getEndDate(),
-             item.getAmount(), item.getRate(), item.getCurrency().name(),
+             item.getAmount(), item.getRate(), item.getCurrency(),
              item.getQuantity(), item.getItemDetails(), toInvoiceItemJson(childItems), toAuditLogJson(auditLogs));
     }
 
@@ -150,7 +150,7 @@ public class InvoiceItemJson extends JsonBase {
         return new InvoiceItem() {
             @Override
             public InvoiceItemType getInvoiceItemType() {
-                return itemType != null ? InvoiceItemType.valueOf(itemType) : null;
+                return itemType;
             }
 
             @Override
@@ -185,7 +185,7 @@ public class InvoiceItemJson extends JsonBase {
 
             @Override
             public Currency getCurrency() {
-                return Currency.valueOf(currency);
+                return currency;
             }
 
             @Override
@@ -345,7 +345,7 @@ public class InvoiceItemJson extends JsonBase {
         return prettyUsageName;
     }
 
-    public String getItemType() {
+    public InvoiceItemType getItemType() {
         return itemType;
     }
 
@@ -367,7 +367,7 @@ public class InvoiceItemJson extends JsonBase {
 
     public BigDecimal getRate() { return rate; }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
index 10568e2..ab65939 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
@@ -25,9 +25,11 @@ import javax.annotation.Nullable;
 
 import org.apache.shiro.util.CollectionUtils;
 import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.api.InvoiceStatus;
 import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.audit.AuditLog;
 
@@ -39,11 +41,11 @@ import com.google.common.collect.Iterables;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Invoice")
+@ApiModel(value="Invoice", parent = JsonBase.class)
 public class InvoiceJson extends JsonBase {
 
     private final BigDecimal amount;
-    private final String currency;
+    private final Currency currency;
     private final UUID invoiceId;
     private final LocalDate invoiceDate;
     private final LocalDate targetDate;
@@ -55,15 +57,15 @@ public class InvoiceJson extends JsonBase {
     private final List<InvoiceItemJson> items;
     private final String bundleKeys;
     private final List<CreditJson> credits;
-    private final String status;
+    private final InvoiceStatus status;
     private final Boolean isParentInvoice;
     private final UUID parentInvoiceId;
     private final UUID parentAccountId;
 
     @JsonCreator
     public InvoiceJson(@JsonProperty("amount") final BigDecimal amount,
-                       @JsonProperty("currency") final String currency,
-                       @JsonProperty("status") final String status,
+                       @JsonProperty("currency") final Currency currency,
+                       @JsonProperty("status") final InvoiceStatus status,
                        @JsonProperty("creditAdj") final BigDecimal creditAdj,
                        @JsonProperty("refundAdj") final BigDecimal refundAdj,
                        @JsonProperty("invoiceId") final UUID invoiceId,
@@ -104,7 +106,7 @@ public class InvoiceJson extends JsonBase {
     }
 
     public InvoiceJson(final Invoice input, final String bundleKeys, final List<CreditJson> credits, final List<AuditLog> auditLogs) {
-        this(input.getChargedAmount(), input.getCurrency().toString(), input.getStatus().toString(), input.getCreditedAmount(), input.getRefundedAmount(),
+        this(input.getChargedAmount(), input.getCurrency(), input.getStatus(), input.getCreditedAmount(), input.getRefundedAmount(),
              input.getId(), input.getInvoiceDate(), input.getTargetDate(), String.valueOf(input.getInvoiceNumber()),
              input.getBalance(), input.getAccountId(), bundleKeys, credits, null, input.isParentInvoice(),
              input.getParentInvoiceId(),
@@ -130,8 +132,8 @@ public class InvoiceJson extends JsonBase {
             }
         }
         this.amount = input.getChargedAmount();
-        this.currency = input.getCurrency().toString();
-        this.status = input.getStatus().toString();
+        this.currency = input.getCurrency();
+        this.status = input.getStatus();
         this.creditAdj = input.getCreditedAmount();
         this.refundAdj = input.getRefundedAmount();
         this.invoiceId = input.getId();
@@ -152,7 +154,7 @@ public class InvoiceJson extends JsonBase {
         return amount;
     }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
@@ -200,7 +202,7 @@ public class InvoiceJson extends JsonBase {
         return credits;
     }
 
-    public String getStatus() {
+    public InvoiceStatus getStatus() {
         return status;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentJson.java
index 8697e9a..c730199 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentJson.java
@@ -24,6 +24,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentAttempt;
 import org.killbill.billing.util.audit.AccountAuditLogs;
@@ -50,7 +51,7 @@ public class InvoicePaymentJson extends PaymentJson {
                               @JsonProperty("purchasedAmount") final BigDecimal purchasedAmount,
                               @JsonProperty("refundedAmount") final BigDecimal refundedAmount,
                               @JsonProperty("creditedAmount") final BigDecimal creditedAmount,
-                              @JsonProperty("currency") final String currency,
+                              @JsonProperty("currency") final Currency currency,
                               @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                               @JsonProperty("transactions") final List<? extends PaymentTransactionJson> transactions,
                               @JsonProperty("paymentAttempts") final List<PaymentAttemptJson> paymentAttempts,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentTransactionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentTransactionJson.java
index 2635d7a..44303e7 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentTransactionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoicePaymentTransactionJson.java
@@ -24,6 +24,8 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.payment.api.TransactionType;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -40,12 +42,12 @@ public class InvoicePaymentTransactionJson extends PaymentTransactionJson {
                                          @JsonProperty("transactionExternalKey") final String transactionExternalKey,
                                          @JsonProperty("paymentId") final UUID paymentId,
                                          @JsonProperty("paymentExternalKey") final String paymentExternalKey,
-                                         @JsonProperty("transactionType") final String transactionType,
+                                         @JsonProperty("transactionType") final TransactionType transactionType,
                                          @JsonProperty("amount") final BigDecimal amount,
-                                         @JsonProperty("currency") final String currency,
+                                         @JsonProperty("currency") final Currency currency,
                                          @JsonProperty("effectiveDate") final DateTime effectiveDate,
                                          @JsonProperty("processedAmount") final BigDecimal processedAmount,
-                                         @JsonProperty("processedCurrency") final String processedCurrency,
+                                         @JsonProperty("processedCurrency") final Currency processedCurrency,
                                          @JsonProperty("status") final String status,
                                          @JsonProperty("gatewayErrorCode") final String gatewayErrorCode,
                                          @JsonProperty("gatewayErrorMsg") final String gatewayErrorMsg,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/JsonBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/JsonBase.java
index 936cb71..0744f99 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/JsonBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/JsonBase.java
@@ -41,12 +41,12 @@ public abstract class JsonBase {
     }
 
     public JsonBase(@Nullable final List<AuditLogJson> auditLogs) {
-        this.auditLogs = auditLogs;
+        this.auditLogs = auditLogs == null ? ImmutableList.<AuditLogJson>of() : auditLogs;
     }
 
     protected static ImmutableList<AuditLogJson> toAuditLogJson(@Nullable final List<AuditLog> auditLogs) {
         if (auditLogs == null) {
-            return null;
+            return ImmutableList.of();
         }
 
         return ImmutableList.<AuditLogJson>copyOf(Collections2.transform(auditLogs, new Function<AuditLog, AuditLogJson>() {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandJson.java
index ffcf1d3..8898e03 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandJson.java
@@ -19,8 +19,6 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
 
-import org.killbill.billing.util.nodes.NodeCommandProperty;
-
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
@@ -28,21 +26,22 @@ import io.swagger.annotations.ApiModel;
 @ApiModel(value="NodeCommand")
 public class NodeCommandJson {
 
-    private final boolean systemCommandType;
+    private final boolean isSystemCommandType;
     private final String nodeCommandType;
     private final List<NodeCommandPropertyJson> nodeCommandProperties;
 
     @JsonCreator
-    public NodeCommandJson(@JsonProperty("systemCommandType") final boolean systemCommandType,
+    public NodeCommandJson(@JsonProperty("isSystemCommandType") final boolean isSystemCommandType,
                            @JsonProperty("nodeCommandType") final String nodeCommandType,
                            @JsonProperty("nodeCommandProperties") final List<NodeCommandPropertyJson> nodeCommandProperties) {
-        this.systemCommandType = systemCommandType;
+        this.isSystemCommandType = isSystemCommandType;
         this.nodeCommandType = nodeCommandType;
         this.nodeCommandProperties = nodeCommandProperties;
     }
 
+    @JsonProperty("isSystemCommandType")
     public boolean isSystemCommandType() {
-        return systemCommandType;
+        return isSystemCommandType;
     }
 
     public String getNodeCommandType() {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueJson.java
index 1e30ce4..5a7a601 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueJson.java
@@ -19,9 +19,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
 
-import org.killbill.billing.catalog.api.CurrencyValueNull;
 import org.killbill.billing.catalog.api.TimeUnit;
-import org.killbill.billing.overdue.api.OverdueApiException;
 import org.killbill.billing.overdue.api.OverdueConfig;
 import org.killbill.billing.overdue.api.OverdueState;
 import org.killbill.billing.overdue.config.DefaultDuration;
@@ -126,8 +124,8 @@ public class OverdueJson {
             final DefaultOverdueState state = new DefaultOverdueState();
             state.setName(cur.getName());
             state.setExternalMessage(cur.getExternalMessage());
-            state.setBlockChanges(cur.getBlockChanges());
-            state.setDisableEntitlement(cur.getDisableEntitlement());
+            state.setBlockChanges(cur.isBlockChanges());
+            state.setDisableEntitlement(cur.isDisableEntitlement());
             state.setSubscriptionCancellationPolicy(cur.getSubscriptionCancellationPolicy());
             state.setClearState(cur.isClearState());
             state.setAutoReevaluationInterval(computeReevaluationInterval(cur.getAutoReevaluationIntervalDays(), prevTimeSinceEarliestUnpaidInvoice, cur.getCondition().getTimeSinceEarliestUnpaidInvoiceEqualsOrExceeds().getNumber()));
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateConfigJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateConfigJson.java
index 9a509ab..e646eb1 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateConfigJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateConfigJson.java
@@ -32,8 +32,8 @@ public class OverdueStateConfigJson {
     private final Boolean isClearState;
     private final OverdueConditionJson condition;
     private final String externalMessage;
-    private final Boolean blockChanges;
-    private final Boolean disableEntitlement;
+    private final Boolean isBlockChanges;
+    private final Boolean isDisableEntitlement;
     private final OverdueCancellationPolicy subscriptionCancellationPolicy;
     private final Integer autoReevaluationIntervalDays;
 
@@ -42,16 +42,16 @@ public class OverdueStateConfigJson {
                                   @JsonProperty("isClearState") final Boolean isClearState,
                                   @JsonProperty("condition") final OverdueConditionJson condition,
                                   @JsonProperty("externalMessage") final String externalMessage,
-                                  @JsonProperty("blockChanges") final Boolean blockChanges,
-                                  @JsonProperty("disableEntitlement") final Boolean disableEntitlement,
+                                  @JsonProperty("isBlockChanges") final Boolean isBlockChanges,
+                                  @JsonProperty("isDisableEntitlement") final Boolean isDisableEntitlement,
                                   @JsonProperty("subscriptionCancellationPolicy") final OverdueCancellationPolicy subscriptionCancellationPolicy,
                                   @JsonProperty("autoReevaluationIntervalDays") final Integer autoReevaluationInterval) {
         this.name = name;
         this.isClearState = isClearState;
         this.condition = condition;
         this.externalMessage = externalMessage;
-        this.blockChanges = blockChanges;
-        this.disableEntitlement = disableEntitlement;
+        this.isBlockChanges = isBlockChanges;
+        this.isDisableEntitlement = isDisableEntitlement;
         this.subscriptionCancellationPolicy = subscriptionCancellationPolicy;
         this.autoReevaluationIntervalDays = autoReevaluationInterval;
     }
@@ -61,8 +61,8 @@ public class OverdueStateConfigJson {
         this.isClearState = input.isClearState();
         this.condition = input.getOverdueCondition() != null ? new OverdueConditionJson(input.getOverdueCondition()) : null;
         this.externalMessage = input.getExternalMessage();
-        this.blockChanges = input.isBlockChanges();
-        this.disableEntitlement = input.isDisableEntitlementAndChangesBlocked();
+        this.isBlockChanges = input.isBlockChanges();
+        this.isDisableEntitlement = input.isDisableEntitlementAndChangesBlocked();
         this.subscriptionCancellationPolicy = input.getOverdueCancellationPolicy();
         Integer tmpAutoReevaluationIntervalDays = null;
         try {
@@ -90,12 +90,14 @@ public class OverdueStateConfigJson {
         return externalMessage;
     }
 
-    public Boolean getBlockChanges() {
-        return blockChanges;
+    @JsonProperty("isBlockChanges")
+    public Boolean isBlockChanges() {
+        return isBlockChanges;
     }
 
-    public Boolean getDisableEntitlement() {
-        return disableEntitlement;
+    @JsonProperty("isDisableEntitlement")
+    public Boolean isDisableEntitlement() {
+        return isDisableEntitlement;
     }
 
     public OverdueCancellationPolicy getSubscriptionCancellationPolicy() {
@@ -129,10 +131,10 @@ public class OverdueStateConfigJson {
         if (externalMessage != null ? !externalMessage.equals(that.externalMessage) : that.externalMessage != null) {
             return false;
         }
-        if (blockChanges != null ? !blockChanges.equals(that.blockChanges) : that.blockChanges != null) {
+        if (isBlockChanges != null ? !isBlockChanges.equals(that.isBlockChanges) : that.isBlockChanges != null) {
             return false;
         }
-        if (disableEntitlement != null ? !disableEntitlement.equals(that.disableEntitlement) : that.disableEntitlement != null) {
+        if (isDisableEntitlement != null ? !isDisableEntitlement.equals(that.isDisableEntitlement) : that.isDisableEntitlement != null) {
             return false;
         }
         if (subscriptionCancellationPolicy != that.subscriptionCancellationPolicy) {
@@ -148,8 +150,8 @@ public class OverdueStateConfigJson {
         result = 31 * result + (isClearState != null ? isClearState.hashCode() : 0);
         result = 31 * result + (condition != null ? condition.hashCode() : 0);
         result = 31 * result + (externalMessage != null ? externalMessage.hashCode() : 0);
-        result = 31 * result + (blockChanges != null ? blockChanges.hashCode() : 0);
-        result = 31 * result + (disableEntitlement != null ? disableEntitlement.hashCode() : 0);
+        result = 31 * result + (isBlockChanges != null ? isBlockChanges.hashCode() : 0);
+        result = 31 * result + (isDisableEntitlement != null ? isDisableEntitlement.hashCode() : 0);
         result = 31 * result + (subscriptionCancellationPolicy != null ? subscriptionCancellationPolicy.hashCode() : 0);
         result = 31 * result + (autoReevaluationIntervalDays != null ? autoReevaluationIntervalDays.hashCode() : 0);
         return result;
@@ -162,8 +164,8 @@ public class OverdueStateConfigJson {
                ", isClearState=" + isClearState +
                ", condition=" + condition +
                ", externalMessage='" + externalMessage + '\'' +
-               ", blockChanges=" + blockChanges +
-               ", disableEntitlement=" + disableEntitlement +
+               ", isBlockChanges=" + isBlockChanges +
+               ", isDisableEntitlement=" + isDisableEntitlement +
                ", subscriptionCancellationPolicy=" + subscriptionCancellationPolicy +
                ", autoReevaluationIntervalDays=" + autoReevaluationIntervalDays +
                '}';
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateJson.java
index ef5f7fa..567ad91 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueStateJson.java
@@ -33,8 +33,8 @@ public class OverdueStateJson {
     private final String name;
     private final String externalMessage;
     private final List<Integer> daysBetweenPaymentRetries;
-    private final Boolean disableEntitlementAndChangesBlocked;
-    private final Boolean blockChanges;
+    private final Boolean isDisableEntitlementAndChangesBlocked;
+    private final Boolean isBlockChanges;
     private final Boolean isClearState;
     private final Integer reevaluationIntervalDays;
 
@@ -42,15 +42,15 @@ public class OverdueStateJson {
     public OverdueStateJson(@JsonProperty("name") final String name,
                             @JsonProperty("externalMessage") final String externalMessage,
                             @JsonProperty("daysBetweenPaymentRetries") final List<Integer> daysBetweenPaymentRetries,
-                            @JsonProperty("disableEntitlementAndChangesBlocked") final Boolean disableEntitlementAndChangesBlocked,
-                            @JsonProperty("blockChanges") final Boolean blockChanges,
-                            @JsonProperty("clearState") final Boolean isClearState,
+                            @JsonProperty("isDisableEntitlementAndChangesBlocked") final Boolean isDisableEntitlementAndChangesBlocked,
+                            @JsonProperty("isBlockChanges") final Boolean isBlockChanges,
+                            @JsonProperty("isClearState") final Boolean isClearState,
                             @JsonProperty("reevaluationIntervalDays") final Integer reevaluationIntervalDays) {
         this.name = name;
         this.externalMessage = externalMessage;
         this.daysBetweenPaymentRetries = daysBetweenPaymentRetries;
-        this.disableEntitlementAndChangesBlocked = disableEntitlementAndChangesBlocked;
-        this.blockChanges = blockChanges;
+        this.isDisableEntitlementAndChangesBlocked = isDisableEntitlementAndChangesBlocked;
+        this.isBlockChanges = isBlockChanges;
         this.isClearState = isClearState;
         this.reevaluationIntervalDays = reevaluationIntervalDays;
     }
@@ -60,8 +60,8 @@ public class OverdueStateJson {
         this.externalMessage = overdueState.getExternalMessage();
         // TODO this is broken if the per tenant system property was updated, but should we really return that in the OverdueState ?
         this.daysBetweenPaymentRetries = paymentConfig.getPaymentFailureRetryDays(null);
-        this.disableEntitlementAndChangesBlocked = overdueState.isDisableEntitlementAndChangesBlocked();
-        this.blockChanges = overdueState.isBlockChanges();
+        this.isDisableEntitlementAndChangesBlocked = overdueState.isDisableEntitlementAndChangesBlocked();
+        this.isBlockChanges = overdueState.isBlockChanges();
         this.isClearState = overdueState.isClearState();
 
         Period reevaluationIntervalPeriod = null;
@@ -89,14 +89,17 @@ public class OverdueStateJson {
         return daysBetweenPaymentRetries;
     }
 
+    @JsonProperty("isDisableEntitlementAndChangesBlocked")
     public Boolean isDisableEntitlementAndChangesBlocked() {
-        return disableEntitlementAndChangesBlocked;
+        return isDisableEntitlementAndChangesBlocked;
     }
 
+    @JsonProperty("isBlockChanges")
     public Boolean isBlockChanges() {
-        return blockChanges;
+        return isBlockChanges;
     }
 
+    @JsonProperty("isClearState")
     public Boolean isClearState() {
         return isClearState;
     }
@@ -112,8 +115,8 @@ public class OverdueStateJson {
         sb.append("{name='").append(name).append('\'');
         sb.append(", externalMessage='").append(externalMessage).append('\'');
         sb.append(", daysBetweenPaymentRetries=").append(daysBetweenPaymentRetries);
-        sb.append(", disableEntitlementAndChangesBlocked=").append(disableEntitlementAndChangesBlocked);
-        sb.append(", blockChanges=").append(blockChanges);
+        sb.append(", isDisableEntitlementAndChangesBlocked=").append(isDisableEntitlementAndChangesBlocked);
+        sb.append(", isBlockChanges=").append(isBlockChanges);
         sb.append(", isClearState=").append(isClearState);
         sb.append(", reevaluationIntervalDays=").append(reevaluationIntervalDays);
         sb.append('}');
@@ -131,13 +134,13 @@ public class OverdueStateJson {
 
         final OverdueStateJson that = (OverdueStateJson) o;
 
-        if (blockChanges != null ? !blockChanges.equals(that.blockChanges) : that.blockChanges != null) {
+        if (isBlockChanges != null ? !isBlockChanges.equals(that.isBlockChanges) : that.isBlockChanges != null) {
             return false;
         }
         if (daysBetweenPaymentRetries != null ? !daysBetweenPaymentRetries.equals(that.daysBetweenPaymentRetries) : that.daysBetweenPaymentRetries != null) {
             return false;
         }
-        if (disableEntitlementAndChangesBlocked != null ? !disableEntitlementAndChangesBlocked.equals(that.disableEntitlementAndChangesBlocked) : that.disableEntitlementAndChangesBlocked != null) {
+        if (isDisableEntitlementAndChangesBlocked != null ? !isDisableEntitlementAndChangesBlocked.equals(that.isDisableEntitlementAndChangesBlocked) : that.isDisableEntitlementAndChangesBlocked != null) {
             return false;
         }
         if (externalMessage != null ? !externalMessage.equals(that.externalMessage) : that.externalMessage != null) {
@@ -161,8 +164,8 @@ public class OverdueStateJson {
         int result = name != null ? name.hashCode() : 0;
         result = 31 * result + (externalMessage != null ? externalMessage.hashCode() : 0);
         result = 31 * result + (daysBetweenPaymentRetries != null ? daysBetweenPaymentRetries.hashCode() : 0);
-        result = 31 * result + (disableEntitlementAndChangesBlocked != null ? disableEntitlementAndChangesBlocked.hashCode() : 0);
-        result = 31 * result + (blockChanges != null ? blockChanges.hashCode() : 0);
+        result = 31 * result + (isDisableEntitlementAndChangesBlocked != null ? isDisableEntitlementAndChangesBlocked.hashCode() : 0);
+        result = 31 * result + (isBlockChanges != null ? isBlockChanges.hashCode() : 0);
         result = 31 * result + (isClearState != null ? isClearState.hashCode() : 0);
         result = 31 * result + (reevaluationIntervalDays != null ? reevaluationIntervalDays.hashCode() : 0);
         return result;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
index 6206614..310077f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
@@ -24,7 +24,9 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.PaymentAttempt;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -32,7 +34,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="PaymentAttempt")
+@ApiModel(value="PaymentAttempt", parent = JsonBase.class)
 public class PaymentAttemptJson extends JsonBase {
 
     private final UUID accountId;
@@ -40,15 +42,14 @@ public class PaymentAttemptJson extends JsonBase {
     private final String paymentExternalKey;
     private final UUID transactionId;
     private final String transactionExternalKey;
-    @ApiModelProperty(dataType = "org.killbill.billing.payment.api.TransactionType")
-    private final String transactionType;
+    private final TransactionType transactionType;
     @ApiModelProperty(dataType = "org.joda.time.DateTime")
     private final DateTime effectiveDate;
     private final String stateName;
     @ApiModelProperty(value = "Transaction amount, required except for void operations")
     private final BigDecimal amount;
     @ApiModelProperty(value = "Amount currency (account currency unless specified)", dataType = "org.killbill.billing.catalog.api.Currency")
-    private final String currency;
+    private final Currency currency;
     // Plugin specific fields
     private final String pluginName;
     private final List<PluginPropertyJson> pluginProperties;
@@ -59,11 +60,11 @@ public class PaymentAttemptJson extends JsonBase {
                               @JsonProperty("paymentExternalKey") final String paymentExternalKey,
                               @JsonProperty("transactionId") final UUID transactionId,
                               @JsonProperty("transactionExternalKey") final String transactionExternalKey,
-                              @JsonProperty("transactionType") final String transactionType,
+                              @JsonProperty("transactionType") final TransactionType transactionType,
                               @JsonProperty("effectiveDate") final DateTime effectiveDate,
                               @JsonProperty("stateName") final String stateName,
                               @JsonProperty("amount") final BigDecimal amount,
-                              @JsonProperty("currency") final String currency,
+                              @JsonProperty("currency") final Currency currency,
                               @JsonProperty("pluginName") final String pluginName,
                               @JsonProperty("pluginProperties") final List<PluginPropertyJson> pluginProperties,
                               @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
@@ -89,11 +90,11 @@ public class PaymentAttemptJson extends JsonBase {
              paymentExternalKey,
              paymentAttempt.getTransactionId(),
              paymentAttempt.getTransactionExternalKey(),
-             paymentAttempt.getTransactionType().toString(),
+             paymentAttempt.getTransactionType(),
              paymentAttempt.getEffectiveDate(),
              paymentAttempt.getStateName(),
              paymentAttempt.getAmount(),
-             paymentAttempt.getCurrency() != null ? paymentAttempt.getCurrency().toString() : null,
+             paymentAttempt.getCurrency() != null ? paymentAttempt.getCurrency() : null,
              paymentAttempt.getPluginName(),
              paymentAttempt.getPluginProperties() == null ? null : toPluginPropertyJson(paymentAttempt.getPluginProperties()),
              toAuditLogJson(attemptsLogs));
@@ -119,7 +120,7 @@ public class PaymentAttemptJson extends JsonBase {
         return transactionExternalKey;
     }
 
-    public String getTransactionType() {
+    public TransactionType getTransactionType() {
         return transactionType;
     }
 
@@ -135,7 +136,7 @@ public class PaymentAttemptJson extends JsonBase {
         return amount;
     }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentJson.java
index 674d00e..4cc6533 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentJson.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentAttempt;
 import org.killbill.billing.payment.api.PaymentTransaction;
@@ -36,7 +37,7 @@ import com.google.common.collect.Iterables;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Payment")
+@ApiModel(value="Payment", parent = JsonBase.class)
 public class PaymentJson extends JsonBase {
 
     private final UUID accountId;
@@ -48,7 +49,7 @@ public class PaymentJson extends JsonBase {
     private final BigDecimal purchasedAmount;
     private final BigDecimal refundedAmount;
     private final BigDecimal creditedAmount;
-    private final String currency;
+    private final Currency currency;
     private final UUID paymentMethodId;
     private final List<? extends PaymentTransactionJson> transactions;
     private final List<PaymentAttemptJson> paymentAttempts;
@@ -63,7 +64,7 @@ public class PaymentJson extends JsonBase {
                        @JsonProperty("purchasedAmount") final BigDecimal purchasedAmount,
                        @JsonProperty("refundedAmount") final BigDecimal refundedAmount,
                        @JsonProperty("creditedAmount") final BigDecimal creditedAmount,
-                       @JsonProperty("currency") final String currency,
+                       @JsonProperty("currency") final Currency currency,
                        @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                        @JsonProperty("transactions") final List<? extends PaymentTransactionJson> transactions,
                        @JsonProperty("paymentAttempts") final List<PaymentAttemptJson> paymentAttempts,
@@ -94,7 +95,7 @@ public class PaymentJson extends JsonBase {
              dp.getPurchasedAmount(),
              dp.getRefundedAmount(),
              dp.getCreditedAmount(),
-             dp.getCurrency() != null ? dp.getCurrency().toString() : null,
+             dp.getCurrency() != null ? dp.getCurrency() : null,
              dp.getPaymentMethodId(),
              getTransactions(dp.getTransactions(), dp.getExternalKey(), accountAuditLogs),
              getAttempts(dp.getPaymentAttempts(), dp.getExternalKey(), accountAuditLogs),
@@ -161,7 +162,7 @@ public class PaymentJson extends JsonBase {
         return creditedAmount;
     }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentMethodJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentMethodJson.java
index 0f72911..50fe61d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentMethodJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentMethodJson.java
@@ -40,7 +40,7 @@ import com.google.common.collect.Collections2;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="PaymentMethod")
+@ApiModel(value="PaymentMethod", parent = JsonBase.class)
 public class PaymentMethodJson extends JsonBase {
 
     private final String externalKey;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentTransactionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentTransactionJson.java
index 7b6c89c..81b8407 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentTransactionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentTransactionJson.java
@@ -23,7 +23,9 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.PaymentTransaction;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -31,7 +33,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="PaymentTransaction")
+@ApiModel(value="PaymentTransaction", parent = JsonBase.class)
 public class PaymentTransactionJson extends JsonBase {
 
     private final UUID transactionId;
@@ -40,7 +42,7 @@ public class PaymentTransactionJson extends JsonBase {
     private final UUID paymentId;
     private final String paymentExternalKey;
     @ApiModelProperty(dataType = "org.killbill.billing.payment.api.TransactionType")
-    private final String transactionType;
+    private final TransactionType transactionType;
     @ApiModelProperty(dataType = "org.joda.time.DateTime")
     private final DateTime effectiveDate;
     @ApiModelProperty(value = "Transaction status, required for state change notifications", dataType = "org.killbill.billing.payment.api.TransactionStatus")
@@ -48,9 +50,9 @@ public class PaymentTransactionJson extends JsonBase {
     @ApiModelProperty(value = "Transaction amount, required except for void operations")
     private final BigDecimal amount;
     @ApiModelProperty(value = "Amount currency (account currency unless specified)", dataType = "org.killbill.billing.catalog.api.Currency")
-    private final String currency;
+    private final Currency currency;
     private final BigDecimal processedAmount;
-    private final String processedCurrency;
+    private final Currency processedCurrency;
     private final String gatewayErrorCode;
     private final String gatewayErrorMsg;
     // Plugin specific fields
@@ -63,12 +65,12 @@ public class PaymentTransactionJson extends JsonBase {
                                   @JsonProperty("transactionExternalKey") final String transactionExternalKey,
                                   @JsonProperty("paymentId") final UUID paymentId,
                                   @JsonProperty("paymentExternalKey") final String paymentExternalKey,
-                                  @JsonProperty("transactionType") final String transactionType,
+                                  @JsonProperty("transactionType") final TransactionType transactionType,
                                   @JsonProperty("amount") final BigDecimal amount,
-                                  @JsonProperty("currency") final String currency,
+                                  @JsonProperty("currency") final Currency currency,
                                   @JsonProperty("effectiveDate") final DateTime effectiveDate,
                                   @JsonProperty("processedAmount") final BigDecimal processedAmount,
-                                  @JsonProperty("processedCurrency") final String processedCurrency,
+                                  @JsonProperty("processedCurrency") final Currency processedCurrency,
                                   @JsonProperty("status") final String status,
                                   @JsonProperty("gatewayErrorCode") final String gatewayErrorCode,
                                   @JsonProperty("gatewayErrorMsg") final String gatewayErrorMsg,
@@ -100,12 +102,12 @@ public class PaymentTransactionJson extends JsonBase {
              transaction.getExternalKey(),
              transaction.getPaymentId(),
              paymentExternalKey,
-             transaction.getTransactionType().toString(),
+             transaction.getTransactionType(),
              transaction.getAmount(),
-             transaction.getCurrency() != null ? transaction.getCurrency().toString() : null,
+             transaction.getCurrency() != null ? transaction.getCurrency() : null,
              transaction.getEffectiveDate(),
              transaction.getProcessedAmount(),
-             transaction.getProcessedCurrency() != null ? transaction.getProcessedCurrency().toString() : null,
+             transaction.getProcessedCurrency() != null ? transaction.getProcessedCurrency() : null,
              transaction.getTransactionStatus() != null ? transaction.getTransactionStatus().toString() : null,
              transaction.getGatewayErrorCode(),
              transaction.getGatewayErrorMsg(),
@@ -127,7 +129,7 @@ public class PaymentTransactionJson extends JsonBase {
         return transactionExternalKey;
     }
 
-    public String getTransactionType() {
+    public TransactionType getTransactionType() {
         return transactionType;
     }
 
@@ -143,7 +145,7 @@ public class PaymentTransactionJson extends JsonBase {
         return amount;
     }
 
-    public String getCurrency() {
+    public Currency getCurrency() {
         return currency;
     }
 
@@ -175,7 +177,7 @@ public class PaymentTransactionJson extends JsonBase {
         return processedAmount;
     }
 
-    public String getProcessedCurrency() {
+    public Currency getProcessedCurrency() {
         return processedCurrency;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PlanDetailJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PlanDetailJson.java
index 50f7350..4cde15d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PlanDetailJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PlanDetailJson.java
@@ -79,7 +79,7 @@ public class PlanDetailJson {
                                                                         try {
                                                                             return new PriceJson(price);
                                                                         } catch (final CurrencyValueNull e) {
-                                                                            return new PriceJson(price.getCurrency().toString(), BigDecimal.ZERO);
+                                                                            return new PriceJson(price.getCurrency(), BigDecimal.ZERO);
                                                                         }
                                                                     }
                                                                 });
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
index cd3eae0..ffda798 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
@@ -31,12 +31,17 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementSourceType;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.Subscription;
 import org.killbill.billing.entitlement.api.SubscriptionEvent;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.audit.AuditLog;
 
@@ -45,7 +50,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Subscription")
+@ApiModel(value="Subscription", parent = JsonBase.class)
 public class SubscriptionJson extends JsonBase {
 
     private final UUID accountId;
@@ -55,22 +60,16 @@ public class SubscriptionJson extends JsonBase {
     private final LocalDate startDate;
     @ApiModelProperty(required = true)
     private final String productName;
-    @ApiModelProperty(dataType = "org.killbill.billing.catalog.api.ProductCategory", required = true)
-    private final String productCategory;
-    @ApiModelProperty(dataType = "org.killbill.billing.catalog.api.BillingPeriod", required = true)
-    private final String billingPeriod;
-    @ApiModelProperty(dataType = "org.killbill.billing.catalog.api.PhaseType")
-    private final String phaseType;
+    private final ProductCategory productCategory;
+    @ApiModelProperty(required = true)
+    private final BillingPeriod billingPeriod;
+    private final PhaseType phaseType;
     @ApiModelProperty(required = true)
     private final String priceList;
     @ApiModelProperty(required = true)
     private final String planName;
-    //@ApiModelProperty(dataType = "org.killbill.billing.entitlement.api.Entitlement.EntitlementState")
-    @ApiModelProperty(dataType = "string", allowableValues = "PENDING,ACTIVE,BLOCKED,CANCELLED")
-    private final String state;
-    //@ApiModelProperty(dataType = "org.killbill.billing.entitlement.api.Entitlement.EntitlementSourceType")
-    @ApiModelProperty(dataType = "string", allowableValues = "NATIVE,MIGRATED,TRANSFERRED")
-    private final String sourceType;
+    private final EntitlementState state;
+    private final EntitlementSourceType sourceType;
     private final LocalDate cancelledDate;
     private final LocalDate chargedThroughDate;
     private final LocalDate billingStartDate;
@@ -79,18 +78,17 @@ public class SubscriptionJson extends JsonBase {
     private final List<EventSubscriptionJson> events;
     private final List<PhasePriceOverrideJson> priceOverrides;
 
-    @ApiModel(value="EventSubscription")
+    @ApiModel(value="EventSubscription", parent = JsonBase.class)
     public static class EventSubscriptionJson extends JsonBase {
 
         private final UUID eventId;
-        private final String billingPeriod;
+        private final BillingPeriod billingPeriod;
         private final LocalDate effectiveDate;
         private final String plan;
         private final String product;
         private final String priceList;
         private final String phase;
-        @ApiModelProperty(dataType = "org.killbill.billing.entitlement.api.SubscriptionEventType")
-        private final String eventType;
+        private final SubscriptionEventType eventType;
         private final Boolean isBlockedBilling;
         private final Boolean isBlockedEntitlement;
         private final String serviceName;
@@ -98,12 +96,12 @@ public class SubscriptionJson extends JsonBase {
 
         @JsonCreator
         public EventSubscriptionJson(@JsonProperty("eventId") final UUID eventId,
-                                     @JsonProperty("billingPeriod") final String billingPeriod,
+                                     @JsonProperty("billingPeriod") final BillingPeriod billingPeriod,
                                      @JsonProperty("effectiveDate") final LocalDate effectiveDate,
                                      @JsonProperty("plan") final String plan,
                                      @JsonProperty("product") final String product,
                                      @JsonProperty("priceList") final String priceList,
-                                     @JsonProperty("eventType") final String eventType,
+                                     @JsonProperty("eventType") final SubscriptionEventType eventType,
                                      @JsonProperty("isBlockedBilling") final Boolean isBlockedBilling,
                                      @JsonProperty("isBlockedEntitlement") final Boolean isBlockedEntitlement,
                                      @JsonProperty("serviceName") final String serviceName,
@@ -134,12 +132,12 @@ public class SubscriptionJson extends JsonBase {
             final PriceList priceList = subscriptionEvent.getNextPriceList() != null ? subscriptionEvent.getNextPriceList() : subscriptionEvent.getPrevPriceList();
             final PlanPhase phase = subscriptionEvent.getNextPhase() != null ? subscriptionEvent.getNextPhase() : subscriptionEvent.getPrevPhase();
             this.eventId = subscriptionEvent.getId();
-            this.billingPeriod = billingPeriod != null ? billingPeriod.toString() : null;
+            this.billingPeriod = billingPeriod;
             this.effectiveDate = subscriptionEvent.getEffectiveDate();
             this.plan = plan != null ? plan.getName() : null;
             this.product = product != null ? product.getName() : null;
             this.priceList = priceList != null ? priceList.getName() : null;
-            this.eventType = subscriptionEvent.getSubscriptionEventType().toString();
+            this.eventType = subscriptionEvent.getSubscriptionEventType();
             this.isBlockedBilling = subscriptionEvent.isBlockedBilling();
             this.isBlockedEntitlement = subscriptionEvent.isBlockedEntitlement();
             this.serviceName = subscriptionEvent.getServiceName();
@@ -165,7 +163,7 @@ public class SubscriptionJson extends JsonBase {
             return eventId;
         }
 
-        public String getBillingPeriod() {
+        public BillingPeriod getBillingPeriod() {
             return billingPeriod;
         }
 
@@ -185,7 +183,7 @@ public class SubscriptionJson extends JsonBase {
             return priceList;
         }
 
-        public String getEventType() {
+        public SubscriptionEventType getEventType() {
             return eventType;
         }
 
@@ -304,13 +302,13 @@ public class SubscriptionJson extends JsonBase {
                             @JsonProperty("externalKey") @Nullable final String externalKey,
                             @JsonProperty("startDate") @Nullable final LocalDate startDate,
                             @JsonProperty("productName") @Nullable final String productName,
-                            @JsonProperty("productCategory") @Nullable final String productCategory,
-                            @JsonProperty("billingPeriod") @Nullable final String billingPeriod,
-                            @JsonProperty("phaseType") @Nullable final String phaseType,
+                            @JsonProperty("productCategory") @Nullable final ProductCategory productCategory,
+                            @JsonProperty("billingPeriod") @Nullable final BillingPeriod billingPeriod,
+                            @JsonProperty("phaseType") @Nullable final PhaseType phaseType,
                             @JsonProperty("priceList") @Nullable final String priceList,
                             @JsonProperty("planName") @Nullable final String planName,
-                            @JsonProperty("state") @Nullable final String state,
-                            @JsonProperty("sourceType") @Nullable final String sourceType,
+                            @JsonProperty("state") @Nullable final EntitlementState state,
+                            @JsonProperty("sourceType") @Nullable final EntitlementSourceType sourceType,
                             @JsonProperty("cancelledDate") @Nullable final LocalDate cancelledDate,
                             @JsonProperty("chargedThroughDate") @Nullable final LocalDate chargedThroughDate,
                             @JsonProperty("billingStartDate") @Nullable final LocalDate billingStartDate,
@@ -355,19 +353,19 @@ public class SubscriptionJson extends JsonBase {
             this.productName = subscription.getLastActiveProduct().getName();
         }
         if (subscription.getLastActiveProductCategory() == null) {
-            this.productCategory = (firstEvent == null || firstEvent.getNextProduct() == null) ? null : firstEvent.getNextProduct().getCategory().name();
+            this.productCategory = (firstEvent == null || firstEvent.getNextProduct() == null) ? null : firstEvent.getNextProduct().getCategory();
         } else {
-            this.productCategory = subscription.getLastActiveProductCategory().name();
+            this.productCategory = subscription.getLastActiveProductCategory();
         }
         if (subscription.getLastActivePlan() == null) {
-            this.billingPeriod = (firstEvent == null || firstEvent.getNextPlan() == null) ? null : firstEvent.getNextPlan().getRecurringBillingPeriod().name();
+            this.billingPeriod = (firstEvent == null || firstEvent.getNextPlan() == null) ? null : firstEvent.getNextPlan().getRecurringBillingPeriod();
         } else {
-            this.billingPeriod = subscription.getLastActivePlan().getRecurringBillingPeriod().toString();
+            this.billingPeriod = subscription.getLastActivePlan().getRecurringBillingPeriod();
         }
         if (subscription.getLastActivePhase() == null) {
-            this.phaseType = (firstEvent == null || firstEvent.getNextPhase() == null) ? null : firstEvent.getNextPhase().getPhaseType().name();
+            this.phaseType = (firstEvent == null || firstEvent.getNextPhase() == null) ? null : firstEvent.getNextPhase().getPhaseType();
         } else {
-            this.phaseType = subscription.getLastActivePhase().getPhaseType().toString();
+            this.phaseType = subscription.getLastActivePhase().getPhaseType();
         }
         if (subscription.getLastActivePriceList() == null) {
             this.priceList = (firstEvent == null || firstEvent.getNextPriceList() == null) ? null : firstEvent.getNextPriceList().getName();
@@ -381,8 +379,8 @@ public class SubscriptionJson extends JsonBase {
         }
 
 
-        this.state = subscription.getState().name();
-        this.sourceType = subscription.getSourceType().name();
+        this.state = subscription.getState();
+        this.sourceType = subscription.getSourceType();
         this.cancelledDate = subscription.getEffectiveEndDate();
         this.chargedThroughDate = subscription.getChargedThroughDate();
         this.billingStartDate = subscription.getBillingStartDate();
@@ -445,15 +443,15 @@ public class SubscriptionJson extends JsonBase {
         return productName;
     }
 
-    public String getProductCategory() {
+    public ProductCategory getProductCategory() {
         return productCategory;
     }
 
-    public String getBillingPeriod() {
+    public BillingPeriod getBillingPeriod() {
         return billingPeriod;
     }
 
-    public String getPhaseType() {
+    public PhaseType getPhaseType() {
         return phaseType;
     }
 
@@ -465,11 +463,11 @@ public class SubscriptionJson extends JsonBase {
         return planName;
     }
 
-    public String getState() {
+    public EntitlementState getState() {
         return state;
     }
 
-    public String getSourceType() {
+    public EntitlementSourceType getSourceType() {
         return sourceType;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
index 687173d..e785239 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
@@ -16,6 +16,7 @@
 
 package org.killbill.billing.jaxrs.json;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
@@ -35,7 +36,7 @@ import com.google.common.collect.ImmutableSet;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="TagDefinition")
+@ApiModel(value="TagDefinition", parent = JsonBase.class)
 public class TagDefinitionJson extends JsonBase {
 
     private final UUID id;
@@ -44,21 +45,21 @@ public class TagDefinitionJson extends JsonBase {
     private final String name;
     @ApiModelProperty(required = true)
     private final String description;
-    private final Set<String> applicableObjectTypes;
+    private final Set<ObjectType> applicableObjectTypes;
 
     @JsonCreator
     public TagDefinitionJson(@JsonProperty("id") final UUID id,
                              @JsonProperty("isControlTag") final Boolean isControlTag,
                              @JsonProperty("name") final String name,
                              @JsonProperty("description") @Nullable final String description,
-                             @JsonProperty("applicableObjectTypes") @Nullable final Set<String> applicableObjectTypes,
+                             @JsonProperty("applicableObjectTypes") @Nullable final List<ObjectType> applicableObjectTypes,
                              @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
         this.id = id;
         this.isControlTag = isControlTag;
         this.name = name;
         this.description = description;
-        this.applicableObjectTypes = applicableObjectTypes;
+        this.applicableObjectTypes = new HashSet<ObjectType>(applicableObjectTypes);
     }
 
     public TagDefinitionJson(final TagDefinition tagDefinition, @Nullable final List<AuditLog> auditLogs) {
@@ -66,16 +67,7 @@ public class TagDefinitionJson extends JsonBase {
              tagDefinition.isControlTag(),
              tagDefinition.getName(),
              tagDefinition.getDescription(),
-             ImmutableSet.<String>copyOf(Collections2.transform(tagDefinition.getApplicableObjectTypes(), new Function<ObjectType, String>() {
-                 @Override
-                 public String apply(@Nullable final ObjectType input) {
-                     if (input == null) {
-                         return "";
-                     } else {
-                         return input.toString();
-                     }
-                 }
-             })),
+             tagDefinition.getApplicableObjectTypes(),
              toAuditLogJson(auditLogs));
     }
 
@@ -96,7 +88,7 @@ public class TagDefinitionJson extends JsonBase {
         return description;
     }
 
-    public Set<String> getApplicableObjectTypes() {
+    public Set<ObjectType> getApplicableObjectTypes() {
         return applicableObjectTypes;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagJson.java
index 67681d1..f3e4bd0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagJson.java
@@ -31,7 +31,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Tag")
+@ApiModel(value="Tag", parent = JsonBase.class)
 public class TagJson extends JsonBase {
 
     private final UUID tagId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantJson.java
index 615ccf0..330785c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantJson.java
@@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(value="Tenant")
+@ApiModel(value="Tenant", parent = JsonBase.class)
 public class TenantJson extends JsonBase {
 
     private final UUID tenantId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index ecf1c9d..1030626 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -154,7 +154,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.ACCOUNTS_PATH)
-@Api(value = JaxrsResource.ACCOUNTS_PATH, description = "Operations on accounts", tags="Account")
+@Api(value = JaxrsResource.ACCOUNTS_PATH, description = "Operations on accounts", tags = "Account")
 public class AccountResource extends JaxRsResourceBase {
 
     private static final String ID_PARAM_NAME = "accountId";
@@ -298,24 +298,22 @@ public class AccountResource extends JaxRsResourceBase {
                                                  subscriptionApi.getSubscriptionBundlesForAccountIdAndExternalKey(accountId, externalKey, tenantContext) :
                                                  subscriptionApi.getSubscriptionBundlesForAccountId(accountId, tenantContext);
 
-
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(account.getId(), auditMode.getLevel(), tenantContext);
 
-
         boolean filter = (null != bundlesFilter && !bundlesFilter.isEmpty());
 
         final Collection<BundleJson> result = Collections2.transform(
                 (filter) ? filterBundles(bundles, Arrays.asList(bundlesFilter.split(","))) : bundles, new Function<SubscriptionBundle, BundleJson>() {
-            @Override
-            public BundleJson apply(final SubscriptionBundle input) {
-                try {
-                    return new BundleJson(input, account.getCurrency(), accountAuditLogs);
-                } catch (final CatalogApiException e) {
-                    // Not the cleanest thing, but guava Api don't allow throw..
-                    throw new RuntimeException(e);
-                }
-            }
-        });
+                    @Override
+                    public BundleJson apply(final SubscriptionBundle input) {
+                        try {
+                            return new BundleJson(input, account.getCurrency(), accountAuditLogs);
+                        } catch (final CatalogApiException e) {
+                            // Not the cleanest thing, but guava Api don't allow throw..
+                            throw new RuntimeException(e);
+                        }
+                    }
+                });
         return Response.status(Status.OK).entity(result).build();
     }
 
@@ -334,7 +332,7 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve an account by external key", response = AccountJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Account not found")})
-    public Response getAccountByKey(@ApiParam(required=true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+    public Response getAccountByKey(@ApiParam(required = true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
                                     @QueryParam(QUERY_ACCOUNT_WITH_BALANCE) @DefaultValue("false") final Boolean accountWithBalance,
                                     @QueryParam(QUERY_ACCOUNT_WITH_BALANCE_AND_CBA) @DefaultValue("false") final Boolean accountWithBalanceAndCBA,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -364,8 +362,9 @@ public class AccountResource extends JaxRsResourceBase {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account data supplied")})
+    @ApiOperation(value = "Create account", response = AccountJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Account created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account data supplied")})
     public Response createAccount(final AccountJson json,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
@@ -379,16 +378,16 @@ public class AccountResource extends JaxRsResourceBase {
         return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", account.getId(), request);
     }
 
-
     @TimedResource
     @PUT
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @Path("/{accountId:" + UUID_PATTERN + "}")
     @ApiOperation(value = "Update account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account data supplied")})
-    public Response updateAccount(final AccountJson json,
-                                  @PathParam("accountId") final UUID accountId,
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account data supplied")})
+    public Response updateAccount(@PathParam("accountId") final UUID accountId,
+                                  final AccountJson json,
                                   @QueryParam(QUERY_ACCOUNT_TREAT_NULL_AS_RESET) @DefaultValue("false") final Boolean treatNullValueAsReset,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
@@ -402,16 +401,16 @@ public class AccountResource extends JaxRsResourceBase {
         } else {
             accountUserApi.updateAccount(accountId, data, context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
         }
-        return getAccount(accountId, false, false, new AuditMode(AuditLevel.NONE.toString()), request);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
-
     @TimedResource
     @DELETE
     @Path("/{accountId:" + UUID_PATTERN + "}")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Close account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
     public Response closeAccount(@PathParam("accountId") final UUID accountId,
                                  @QueryParam(QUERY_CANCEL_ALL_SUBSCRIPTIONS) @DefaultValue("false") final Boolean cancelAllSubscriptions,
                                  @QueryParam(QUERY_WRITE_OFF_UNPAID_INVOICES) @DefaultValue("false") final Boolean writeOffUnpaidInvoices,
@@ -467,7 +466,7 @@ public class AccountResource extends JaxRsResourceBase {
         }
 
         final BlockingStateJson blockingState = new BlockingStateJson(accountId, "CLOSE_ACCOUNT", "account-service", true, false, false, null, BlockingStateType.ACCOUNT, null);
-        addBlockingState(blockingState, accountId, BlockingStateType.ACCOUNT, null, ImmutableList.<String>of(), createdBy, reason, comment, request);
+        addBlockingState(blockingState, accountId, accountId, BlockingStateType.ACCOUNT, null, ImmutableList.<String>of(), createdBy, reason, comment, request, null);
 
         if (removeFutureNotifications) {
             final Long tenantRecordId = recordIdApi.getRecordId(callContext.getTenantId(), ObjectType.TENANT, callContext);
@@ -477,8 +476,7 @@ public class AccountResource extends JaxRsResourceBase {
                 notificationQueue.removeFutureNotificationsForSearchKeys(accountRecordId, tenantRecordId);
             }
         }
-
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -489,8 +487,8 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getAccountTimeline(@PathParam("accountId") final UUID accountId,
-                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @QueryParam(QUERY_PARALLEL) @DefaultValue("false") final Boolean parallel,
+                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, SubscriptionApiException, InvoiceApiException, CatalogApiException {
 
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
@@ -639,7 +637,8 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + EMAIL_NOTIFICATIONS)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve account email notification", response = InvoiceEmailJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getEmailNotificationsForAccount(@PathParam("accountId") final UUID accountId,
                                                     @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
@@ -655,10 +654,11 @@ public class AccountResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Set account email notification")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response setEmailNotificationsForAccount(final InvoiceEmailJson json,
-                                                    @PathParam("accountId") final UUID accountId,
+    public Response setEmailNotificationsForAccount(@PathParam("accountId") final UUID accountId,
+                                                    final InvoiceEmailJson json,
                                                     @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                     @HeaderParam(HDR_REASON) final String reason,
                                                     @HeaderParam(HDR_COMMENT) final String comment,
@@ -672,19 +672,20 @@ public class AccountResource extends JaxRsResourceBase {
         mutableAccountData.setIsNotifiedForInvoices(json.isNotifiedForInvoices());
         accountUserApi.updateAccount(accountId, mutableAccountData, callContext);
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     /*
      * ************************** INVOICE CBA REBALANCING ********************************
      */
     @TimedResource
-    @POST
+    @PUT
     @Path("/{accountId:" + UUID_PATTERN + "}/" + CBA_REBALANCING)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Rebalance account CBA")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
     public Response rebalanceExistingCBAOnAccount(@PathParam("accountId") final UUID accountId,
                                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                   @HeaderParam(HDR_REASON) final String reason,
@@ -692,7 +693,7 @@ public class AccountResource extends JaxRsResourceBase {
                                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         invoiceApi.consumeExstingCBAOnAccountWithUnpaidInvoices(accountId, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -707,13 +708,13 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account invoices", response = InvoiceJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getInvoices(@PathParam("accountId") final UUID accountId,
-                                @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
-                                @QueryParam(QUERY_WITH_MIGRATION_INVOICES) @DefaultValue("false") final boolean withMigrationInvoices,
-                                @QueryParam(QUERY_UNPAID_INVOICES_ONLY) @DefaultValue("false") final boolean unpaidInvoicesOnly,
-                                @QueryParam(QUERY_INCLUDE_VOIDED_INVOICES) @DefaultValue("false") final boolean includeVoidedInvoices,
-                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
+    public Response getInvoicesForAccount(@PathParam("accountId") final UUID accountId,
+                                          @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
+                                          @QueryParam(QUERY_WITH_MIGRATION_INVOICES) @DefaultValue("false") final boolean withMigrationInvoices,
+                                          @QueryParam(QUERY_UNPAID_INVOICES_ONLY) @DefaultValue("false") final boolean unpaidInvoicesOnly,
+                                          @QueryParam(QUERY_INCLUDE_VOIDED_INVOICES) @DefaultValue("false") final boolean includeVoidedInvoices,
+                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         // Verify the account exists
@@ -746,10 +747,10 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getInvoicePayments(@PathParam("accountId") final UUID accountId,
-                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                        @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
                                        @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
@@ -771,8 +772,8 @@ public class AccountResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Path("/{accountId:" + UUID_PATTERN + "}/" + INVOICE_PAYMENTS)
     @ApiOperation(value = "Trigger a payment for all unpaid invoices")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
-                           @ApiResponse(code = 404, message = "Account not found")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 404, message = "Invalid account id supplied")})
     public Response payAllInvoices(@PathParam("accountId") final UUID accountId,
                                    @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                    @QueryParam(QUERY_PAYMENT_AMOUNT) final BigDecimal paymentAmount,
@@ -815,7 +816,7 @@ public class AccountResource extends JaxRsResourceBase {
         if (externalPayment && remainingRequestPayment.compareTo(BigDecimal.ZERO) > 0) {
             invoiceApi.insertCredit(account.getId(), remainingRequestPayment, clock.getUTCToday(), account.getCurrency(), true, "pay all invoices", null, callContext);
         }
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -823,11 +824,12 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiOperation(value = "Add a payment method", response = PaymentMethodJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment method created"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response createPaymentMethod(final PaymentMethodJson json,
-                                        @PathParam("accountId") final UUID accountId,
+    public Response createPaymentMethod(@PathParam("accountId") final UUID accountId,
+                                        final PaymentMethodJson json,
                                         @QueryParam(QUERY_PAYMENT_METHOD_IS_DEFAULT) @DefaultValue("false") final Boolean isDefault,
                                         @QueryParam(QUERY_PAY_ALL_UNPAID_INVOICES) @DefaultValue("false") final Boolean payAllUnpaidInvoices,
                                         @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
@@ -852,7 +854,6 @@ public class AccountResource extends JaxRsResourceBase {
             return Response.status(Status.BAD_REQUEST).build();
         }
 
-
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
         final UUID paymentMethodId = paymentApi.addPaymentMethodWithPaymentControl(account, data.getExternalKey(), data.getPluginName(), isDefault, data.getPluginDetail(), pluginProperties, paymentOptions, callContext);
         if (payAllUnpaidInvoices && unpaidInvoices.size() > 0) {
@@ -870,12 +871,12 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account payment methods", response = PaymentMethodJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getPaymentMethods(@PathParam("accountId") final UUID accountId,
-                                      @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
-                                      @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                      @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
-                                      @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
+    public Response getPaymentMethodsForAccount(@PathParam("accountId") final UUID accountId,
+                                                @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                                @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                                @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
@@ -893,11 +894,12 @@ public class AccountResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @POST
+    @PUT
     @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS + "/refresh")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Refresh account payment methods")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response refreshPaymentMethods(@PathParam("accountId") final UUID accountId,
                                           @QueryParam(QUERY_PAYMENT_PLUGIN_NAME) final String pluginName,
@@ -917,7 +919,7 @@ public class AccountResource extends JaxRsResourceBase {
             paymentApi.refreshPaymentMethods(account, pluginProperties, callContext);
         }
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -926,7 +928,8 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS + "/{paymentMethodId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS_DEFAULT_PATH_POSTFIX)
     @ApiOperation(value = "Set the default payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or payment method id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id or payment method id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response setDefaultPaymentMethod(@PathParam("accountId") final UUID accountId,
                                             @PathParam("paymentMethodId") final UUID paymentMethodId,
@@ -948,7 +951,7 @@ public class AccountResource extends JaxRsResourceBase {
                 createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), paymentMethodId, false, null, null, pluginProperties, callContext);
             }
         }
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     /*
@@ -960,12 +963,12 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve account payments", response = PaymentJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response getPayments(@PathParam("accountId") final UUID accountId,
-                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
-                                @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
-                                @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
+    public Response getPaymentsForAccount(@PathParam("accountId") final UUID accountId,
+                                          @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
+                                          @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final List<Payment> payments = paymentApi.getAccountPayments(accountId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
@@ -984,7 +987,7 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/" + PAYMENTS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Trigger a payment using the account external key (authorization, purchase or credit)")
+    @ApiOperation(value = "Trigger a payment using the account external key (authorization, purchase or credit)", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid account external key supplied"),
                            @ApiResponse(code = 404, message = "Account not found"),
@@ -994,7 +997,7 @@ public class AccountResource extends JaxRsResourceBase {
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
     public Response processPaymentByExternalKey(@MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
-                                                @ApiParam(required=true)  @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+                                                @ApiParam(required = true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
                                                 @QueryParam(QUERY_PAYMENT_METHOD_ID) final UUID paymentMethodId,
                                                 @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -1014,7 +1017,7 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENTS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Trigger a payment (authorization, purchase or credit)")
+    @ApiOperation(value = "Trigger a payment (authorization, purchase or credit)", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found"),
@@ -1023,8 +1026,8 @@ public class AccountResource extends JaxRsResourceBase {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response processPayment(@MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
-                                   @PathParam("accountId") final UUID accountId,
+    public Response processPayment(@PathParam("accountId") final UUID accountId,
+                                   @MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
                                    @QueryParam(QUERY_PAYMENT_METHOD_ID) final UUID inputPaymentMethodId,
                                    @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                    @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -1052,7 +1055,7 @@ public class AccountResource extends JaxRsResourceBase {
                              json.getAmount(), "PaymentTransactionJson amount needs to be set");
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
+        final Currency currency = json.getCurrency() == null ? account.getCurrency() : json.getCurrency();
         final UUID paymentId = json.getPaymentId();
 
         //
@@ -1064,9 +1067,9 @@ public class AccountResource extends JaxRsResourceBase {
         if (paymentId != null) {
             final Payment initialPayment = paymentApi.getPayment(paymentId, false, false, pluginProperties, callContext);
             final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment,
-                                                                                   json != null ? json.getTransactionId() : null,
-                                                                                   json != null ? json.getTransactionExternalKey() : null,
-                                                                                   json != null ? json.getTransactionType() : null);
+                                                                                                     json != null ? json.getTransactionId() : null,
+                                                                                                     json != null ? json.getTransactionExternalKey() : null,
+                                                                                                     json != null ? json.getTransactionType() : null);
             // If transaction was already completed, return early (See #626)
             if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
                 return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
@@ -1078,8 +1081,7 @@ public class AccountResource extends JaxRsResourceBase {
         }
         validatePaymentMethodForAccount(account.getId(), paymentMethodId, callContext);
 
-
-        final TransactionType transactionType = TransactionType.valueOf(json.getTransactionType());
+        final TransactionType transactionType = json.getTransactionType();
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
         final Payment result;
         switch (transactionType) {
@@ -1156,21 +1158,23 @@ public class AccountResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @PUT
+    @POST
     @Path("/{accountId:" + UUID_PATTERN + "}/" + BLOCK)
     @Consumes(APPLICATION_JSON)
-    @ApiOperation(value = "Block an account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiOperation(value = "Block an account", response = BlockingStateJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Blocking state created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response addAccountBlockingState(final BlockingStateJson json,
-                                           @PathParam(ID_PARAM_NAME) final UUID id,
-                                           @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                           @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 HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
-        return addBlockingState(json, id, BlockingStateType.ACCOUNT, requestedDate, pluginPropertiesString, createdBy, reason, comment, request);
+    public Response addAccountBlockingState(@PathParam(ID_PARAM_NAME) final UUID id,
+                                            final BlockingStateJson json,
+                                            @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                            @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                            @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 HttpServletRequest request,
+                                            @javax.ws.rs.core.Context final UriInfo uriInfo) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
+        return addBlockingState(json, id, id, BlockingStateType.ACCOUNT, requestedDate, pluginPropertiesString, createdBy, reason, comment, request, uriInfo);
     }
 
 
@@ -1182,7 +1186,7 @@ public class AccountResource extends JaxRsResourceBase {
     @GET
     @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve account custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve account custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getAccountCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -1213,33 +1217,34 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to account", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
+    public Response createAccountCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request,
+                                              @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(accountId, customFields, context.createCallContextWithAccountId(accountId, createdBy, reason,
                                                                                                         comment, request), uriInfo, request);
     }
 
-
     @TimedResource
     @PUT
     @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
+    public Response modifyAccountCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(accountId, customFields, context.createCallContextWithAccountId(accountId, createdBy, reason,
                                                                                                         comment, request));
     }
@@ -1250,13 +1255,14 @@ public class AccountResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
+    public Response deleteAccountCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                                              @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(accountId, customFieldList,
                                         context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
     }
@@ -1269,12 +1275,12 @@ public class AccountResource extends JaxRsResourceBase {
     @GET
     @Path("/{accountId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve account tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve account tags", response = TagJson.class, responseContainer = "List", nickname = "getAccountTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
         return super.getTags(accountId, accountId, auditMode, includedDeleted, context.createTenantContextWithAccountId(accountId, request));
     }
@@ -1288,8 +1294,8 @@ public class AccountResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getAllTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                @QueryParam(QUERY_OBJECT_TYPE) final ObjectType objectType,
-                               @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                               @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final List<Tag> tags = objectType != null ?
@@ -1301,16 +1307,18 @@ public class AccountResource extends JaxRsResourceBase {
     @TimedResource
     @POST
     @Path("/{accountId:" + UUID_PATTERN + "}/" + TAGS)
+    @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to account", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
+    public Response createAccountTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                                      final List<UUID> tagList,
+                                      @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,
+                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(accountId, tagList, uriInfo,
                                 context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request), request);
     }
@@ -1321,20 +1329,20 @@ public class AccountResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied or account does not have a default payment method (AUTO_PAY_OFF tag only)")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException, AccountApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied or account does not have a default payment method (AUTO_PAY_OFF tag only)")})
+    public Response deleteAccountTags(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                                      @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                      @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 HttpServletRequest request) throws TagApiException, AccountApiException {
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         // Look if there is an AUTO_PAY_OFF for that account and check if the account has a default paymentMethod
         // If not we can't remove the AUTO_PAY_OFF tag
-        final Collection<UUID> tagDefinitionUUIDs = getTagDefinitionUUIDs(tagList);
         boolean isTagAutoPayOff = false;
-        for (final UUID cur : tagDefinitionUUIDs) {
+        for (final UUID cur : tagList) {
             if (cur.equals(ControlTagType.AUTO_PAY_OFF.getId())) {
                 isTagAutoPayOff = true;
                 break;
@@ -1376,11 +1384,12 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + EMAILS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add account email")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiOperation(value = "Add account email", response = AccountEmailJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Email created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response addEmail(final AccountEmailJson json,
-                             @PathParam(ID_PARAM_NAME) final UUID accountId,
+    public Response addEmail(@PathParam(ID_PARAM_NAME) final UUID accountId,
+                             final AccountEmailJson json,
                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                              @HeaderParam(HDR_REASON) final String reason,
                              @HeaderParam(HDR_COMMENT) final String comment,
@@ -1390,7 +1399,6 @@ public class AccountResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json.getEmail(), "AccountEmailJson email needs to be set");
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
-
         // Make sure the account exist or we will confuse the history and auditing code
         accountUserApi.getAccountById(accountId, callContext);
 
@@ -1416,7 +1424,8 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + EMAILS + "/{email}")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Delete email from account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
     public Response removeEmail(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                 @PathParam("email") final String email,
                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -1431,7 +1440,7 @@ public class AccountResource extends JaxRsResourceBase {
                 accountUserApi.removeEmail(accountId, accountEmail, context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
             }
         }
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -1482,12 +1491,13 @@ public class AccountResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @POST
+    @PUT
     @Path("/{childAccountId:" + UUID_PATTERN + "}/" + TRANSFER_CREDIT)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Move a given child credit to the parent level")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Account does not have credit"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Account does not have credit"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response transferChildCreditToParent(@PathParam("childAccountId") final UUID childAccountId,
                                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -1499,7 +1509,7 @@ public class AccountResource extends JaxRsResourceBase {
         final CallContext callContext = context.createCallContextWithAccountId(childAccountId, createdBy, reason, comment, request);
 
         invoiceApi.transferChildCreditToParent(childAccountId, callContext);
-        return Response.status(Response.Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     /*
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
index 443cba2..20dc70b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
@@ -102,6 +102,7 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
 
 @Singleton
 @Path(JaxrsResource.ADMIN_PATH)
@@ -149,9 +150,11 @@ public class AdminResource extends JaxRsResourceBase {
 
     @GET
     @Path("/queues")
-    @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Get queues entries", response = Response.class, hidden=true)
-    @ApiResponses(value = {})
+    @Produces(APPLICATION_OCTET_STREAM)
+    @ApiOperation(value = "Get queues entries", response = Response.class)
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "Success"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
+                           @ApiResponse(code = 404, message = "Account not found")})
     public Response getQueueEntries(@QueryParam("accountId") final UUID accountId,
                                     @QueryParam("queueName") final String queueName,
                                     @QueryParam("serviceName") final String serviceName,
@@ -231,10 +234,11 @@ public class AdminResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/payments/{paymentId:" + UUID_PATTERN + "}/transactions/{paymentTransactionId:" + UUID_PATTERN + "}")
     @ApiOperation(value = "Update existing paymentTransaction and associated payment state")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account data supplied")})
-    public Response updatePaymentTransactionState(final AdminPaymentJson json,
-                                                  @PathParam("paymentId") final UUID paymentId,
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account data supplied")})
+    public Response updatePaymentTransactionState(@PathParam("paymentId") final UUID paymentId,
                                                   @PathParam("paymentTransactionId") final UUID paymentTransactionId,
+                                                  final AdminPaymentJson json,
                                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                   @HeaderParam(HDR_REASON) final String reason,
                                                   @HeaderParam(HDR_COMMENT) final String comment,
@@ -252,7 +256,7 @@ public class AdminResource extends JaxRsResourceBase {
 
         adminPaymentApi.fixPaymentTransactionState(payment, paymentTransaction, TransactionStatus.valueOf(json.getTransactionStatus()),
                                                    json.getLastSuccessPaymentState(), json.getCurrentPaymentStateName(), ImmutableList.<PluginProperty>of(), callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @POST
@@ -260,7 +264,7 @@ public class AdminResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/invoices")
     @ApiOperation(value = "Trigger an invoice generation for all parked accounts")
-    @ApiResponses(value = {})
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "Successful operation")})
     public Response triggerInvoiceGenerationForParkedAccounts(@QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                                               @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -322,7 +326,8 @@ public class AdminResource extends JaxRsResourceBase {
     @Path("/" + CACHE)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Invalidates the given Cache if specified, otherwise invalidates all caches")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Cache name does not exist or is not alive")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Cache name does not exist or is not alive")})
     public Response invalidatesCache(@QueryParam("cacheName") final String cacheName,
                                      @javax.ws.rs.core.Context final HttpServletRequest request) {
         if (null != cacheName && !cacheName.isEmpty()) {
@@ -338,14 +343,15 @@ public class AdminResource extends JaxRsResourceBase {
             // if not given a specific cacheName, clear all
             cacheControllerDispatcher.clearAll();
         }
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @DELETE
     @Path("/" + CACHE + "/" + ACCOUNTS + "/{accountId:" + UUID_PATTERN + "}/")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Invalidates Caches per account level")
-    @ApiResponses(value = {})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied")})
     public Response invalidatesCacheByAccount(@PathParam("accountId") final UUID accountId,
                                               @javax.ws.rs.core.Context final HttpServletRequest request) {
 
@@ -364,16 +370,15 @@ public class AdminResource extends JaxRsResourceBase {
         final CacheController<UUID, Integer> accountBCDCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_BCD);
         accountBCDCacheController.remove(accountId);
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @DELETE
     @Path("/" + CACHE + "/" + TENANTS)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Invalidates Caches per tenant level")
-    @ApiResponses(value = {})
-    public Response invalidatesCacheByTenant(@QueryParam("tenantApiKey") final String tenantApiKey,
-                                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
+    public Response invalidatesCacheByTenant(@javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
 
         // creating Tenant Context from Request
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -418,27 +423,27 @@ public class AdminResource extends JaxRsResourceBase {
         final CacheController<Long, Catalog> tenantCatalogCacheController = cacheControllerDispatcher.getCacheController(CacheType.TENANT_CATALOG);
         tenantCatalogCacheController.remove(tenantRecordId);
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
-    @POST
+    @PUT
     @Path("/" + HEALTHCHECK)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Put the host back into rotation")
-    @ApiResponses(value = {})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
     public Response putInRotation(@javax.ws.rs.core.Context final HttpServletRequest request) {
         killbillHealthcheck.putInRotation();
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @DELETE
     @Path("/" + HEALTHCHECK)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Put the host out of rotation")
-    @ApiResponses(value = {})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
     public Response putOutOfRotation(@javax.ws.rs.core.Context final HttpServletRequest request) {
         killbillHealthcheck.putOutOfRotation();
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     private Iterable<NotificationEventWithMetadata<NotificationEvent>> getNotifications(@Nullable final String queueName,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
index 476d72a..89af32f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
@@ -70,6 +70,7 @@ import org.killbill.billing.util.api.TagUserApi;
 import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
@@ -132,7 +133,7 @@ public class BundleResource extends JaxRsResourceBase {
     @TimedResource
     @GET
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a bundle by external key", response = BundleJson.class)
+    @ApiOperation(value = "Retrieve a bundle by external key", response = BundleJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Bundle not found")})
     public Response getBundleByKey(@ApiParam(required=true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
                                    @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
@@ -233,7 +234,8 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Pause a bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
     public Response pauseBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                 @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
@@ -246,7 +248,7 @@ public class BundleResource extends JaxRsResourceBase {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
         entitlementApi.pause(bundleId, inputLocalDate, pluginProperties, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -255,7 +257,8 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Resume a bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
     public Response resumeBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                  @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
@@ -268,25 +271,29 @@ public class BundleResource extends JaxRsResourceBase {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
         entitlementApi.resume(bundleId, inputLocalDate, pluginProperties, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
-    @PUT
+    @POST
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + BLOCK)
     @Consumes(APPLICATION_JSON)
-    @ApiOperation(value = "Block a bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
+    @ApiOperation(value = "Block a bundle", response = BlockingStateJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Blocking state created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response addBundleBlockingState(final BlockingStateJson json,
-                                           @PathParam(ID_PARAM_NAME) final UUID id,
+    public Response addBundleBlockingState(@PathParam(ID_PARAM_NAME) final UUID id,
+                                           final BlockingStateJson json,
                                            @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                            @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                            @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 HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
-        return addBlockingState(json, id, BlockingStateType.SUBSCRIPTION_BUNDLE, requestedDate, pluginPropertiesString, createdBy, reason, comment, request);
+                                           @javax.ws.rs.core.Context final HttpServletRequest request,
+                                           @javax.ws.rs.core.Context final UriInfo uriInfo) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
+        final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
+        final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(id, tenantContext);
+        return addBlockingState(json, bundle.getAccountId(), id, BlockingStateType.SUBSCRIPTION_BUNDLE, requestedDate, pluginPropertiesString, createdBy, reason, comment, request, uriInfo);
     }
 
 
@@ -295,7 +302,7 @@ public class BundleResource extends JaxRsResourceBase {
     @GET
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve bundle custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve bundle custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getBundleCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -308,15 +315,16 @@ public class BundleResource extends JaxRsResourceBase {
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to bundle", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied")})
+    public Response createBundleCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                             final List<CustomFieldJson> customFields,
+                                             @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 HttpServletRequest request,
+                                             @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(bundleId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -327,13 +335,14 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied")})
+    public Response modifyBundleCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                             final List<CustomFieldJson> customFields,
+                                             @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(bundleId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -347,13 +356,14 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied")})
+    public Response deleteBundleCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                             @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                             @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(bundleId, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -362,12 +372,12 @@ public class BundleResource extends JaxRsResourceBase {
     @GET
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve bundle tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve bundle tags", response = TagJson.class, responseContainer = "List", nickname = "getBundleTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, tenantContext);
@@ -375,17 +385,18 @@ public class BundleResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @PUT
+    @POST
     @Path("/{bundleId:" + UUID_PATTERN + "}")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Transfer a bundle to another account")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id, requested date or policy supplied"),
+    @ApiOperation(value = "Transfer a bundle to another account", response = BundleJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Bundle transferred successfully"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id, requested date or policy supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response transferBundle(final BundleJson json,
-                                   @PathParam(ID_PARAM_NAME) final UUID bundleId,
+    public Response transferBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                   final BundleJson json,
                                    @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-                                   @QueryParam(QUERY_BILLING_POLICY) @DefaultValue("END_OF_TERM") final String policyString,
+                                   @QueryParam(QUERY_BILLING_POLICY) @DefaultValue("END_OF_TERM") final BillingActionPolicy billingPolicy,
                                    @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                    @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                    @HeaderParam(HDR_REASON) final String reason,
@@ -396,13 +407,12 @@ public class BundleResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json.getAccountId(), "BundleJson accountId needs to be set");
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final BillingActionPolicy policy = BillingActionPolicy.valueOf(policyString.toUpperCase());
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, callContext);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
 
-        final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), json.getAccountId(), bundle.getExternalKey(), inputLocalDate, policy, pluginProperties, callContext);
+        final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), json.getAccountId(), bundle.getExternalKey(), inputLocalDate, billingPolicy, pluginProperties, callContext);
         return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", newBundleId, request);
     }
 
@@ -412,10 +422,11 @@ public class BundleResource extends JaxRsResourceBase {
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + RENAME_KEY)
     @Consumes(APPLICATION_JSON)
     @ApiOperation(value = "Update a bundle externalKey")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid argumnent supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid argumnent supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response renameExternalKey(final BundleJson json,
-                                      @PathParam(ID_PARAM_NAME) final UUID bundleId,
+    public Response renameExternalKey(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                      final BundleJson json,
                                       /* @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, */
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
@@ -428,7 +439,7 @@ public class BundleResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         subscriptionApi.updateExternalKey(bundleId, json.getExternalKey(), callContext);
-        return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", bundleId, request);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -438,15 +449,16 @@ public class BundleResource extends JaxRsResourceBase {
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to bundle", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied")})
+    public Response createBundleTags(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                     final List<UUID> tagList,
+                                     @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,
+                                     @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(bundleId, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -457,13 +469,14 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from bundle")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID bundleId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid bundle id supplied")})
+    public Response deleteBundleTags(@PathParam(ID_PARAM_NAME) final UUID bundleId,
+                                     @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                     @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(bundleId, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
index 95a4458..adb0acb 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
@@ -81,10 +81,11 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_XML;
 
 @Singleton
 @Path(JaxrsResource.CATALOG_PATH)
@@ -110,14 +111,19 @@ public class CatalogResource extends JaxRsResourceBase {
         this.subscriptionApi = subscriptionApi;
     }
 
+    //
+    // We mark this resource as hidden from a swagger point of view and create another one with a different Path below
+    // to hack around the restrictions of having only one type of HTTP verb per Path
+    // see https://github.com/killbill/killbill/issues/913
+    //
     @TimedResource
     @GET
-    @Produces(APPLICATION_XML)
+    @Produces(TEXT_XML)
     @ApiOperation(value = "Retrieve the full catalog as XML", response = String.class, hidden = true)
     @ApiResponses(value = {})
-    public Response getCatalogXml(@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-                                  @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
-                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+    public Response getCatalogXmlOriginal(@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                          @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
         final TenantContext tenantContext = accountId != null ?
                                             context.createTenantContextWithAccountId(accountId, request) :
                                             context.createTenantContextNoAccountId(request);
@@ -145,11 +151,25 @@ public class CatalogResource extends JaxRsResourceBase {
     }
 
     @TimedResource
+    @Path("/xml")
+    @GET
+    @Produces(TEXT_XML)
+    @ApiOperation(value = "Retrieve the full catalog as XML", response = String.class)
+    @ApiResponses(value = {})
+    public Response getCatalogXml(@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                  @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
+                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+        return getCatalogXmlOriginal(requestedDate, accountId, request);
+    }
+
+
+
+    @TimedResource
     @POST
-    @Consumes(APPLICATION_XML)
-    @ApiOperation(value = "Upload the full catalog as XML")
+    @Consumes(TEXT_XML)
+    @ApiOperation(value = "Upload the full catalog as XML", hidden=true)
     @ApiResponses(value = {})
-    public Response uploadCatalogXml(final String catalogXML,
+    public Response uploadCatalogXmlOriginal(final String catalogXML,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
                                      @HeaderParam(HDR_COMMENT) final String comment,
@@ -161,9 +181,25 @@ public class CatalogResource extends JaxRsResourceBase {
     }
 
     @TimedResource
+    @POST
+    @Path("/xml")
+    @Consumes(TEXT_XML)
+    @ApiOperation(value = "Upload the full catalog as XML", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Catalog XML created successfully")})
+    public Response uploadCatalogXml(final String catalogXML,
+                                     @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 HttpServletRequest request,
+                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        return uploadCatalogXmlOriginal(catalogXML, createdBy, reason, comment, request, uriInfo);
+    }
+
+
+    @TimedResource
     @GET
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve the catalog as JSON", response = StaticCatalog.class)
+    @ApiOperation(value = "Retrieve the catalog as JSON", responseContainer = "List", response = CatalogJson.class)
     @ApiResponses(value = {})
     public Response getCatalogJson(@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                    @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
@@ -196,13 +232,11 @@ public class CatalogResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve a list of catalog versions", response = DateTime.class, responseContainer = "List")
     @ApiResponses(value = {})
-    public Response getCatalogVersionJson(@QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
-                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
-
+    public Response getCatalogVersions(@QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
+                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
         final TenantContext tenantContext = accountId != null ?
                                             context.createTenantContextWithAccountId(accountId, request) :
                                             context.createTenantContextNoAccountId(request);
-
         final VersionedCatalog catalog = (VersionedCatalog) catalogUserApi.getCatalog(catalogName, tenantContext);
 
         final List<DateTime> result = new ArrayList<DateTime>();
@@ -408,8 +442,8 @@ public class CatalogResource extends JaxRsResourceBase {
     @Path("/simplePlan")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Upload the full catalog as XML")
-    @ApiResponses(value = {})
+    @ApiOperation(value = "Add a simple plan entry in the current version of the catalog", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created new plan successfully")})
     public Response addSimplePlan(final SimplePlanJson simplePlan,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
@@ -433,7 +467,7 @@ public class CatalogResource extends JaxRsResourceBase {
 
     @DELETE
     @ApiOperation(value = "Delete all versions for a per tenant catalog")
-    @ApiResponses(value = {})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
     public Response deleteCatalog(@HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
                                   @HeaderParam(HDR_COMMENT) final String comment,
@@ -441,7 +475,7 @@ public class CatalogResource extends JaxRsResourceBase {
                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException, CatalogApiException {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         catalogUserApi.deleteCatalog(callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
index f5abcdf..c4f3a9c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
@@ -103,8 +103,9 @@ public class CreditResource extends JaxRsResourceBase {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create a credit")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiOperation(value = "Create a credit", response = CreditJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created credit successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response createCredit(final CreditJson json,
                                  @QueryParam(QUERY_AUTO_COMMIT) @DefaultValue("false") final Boolean autoCommit,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ExportResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ExportResource.java
index aeccced..e40ea0e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ExportResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ExportResource.java
@@ -28,6 +28,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 
 import org.killbill.billing.account.api.AccountUserApi;
@@ -48,7 +49,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
 
 @Singleton
 @Path(JaxrsResource.EXPORT_PATH)
@@ -74,9 +75,10 @@ public class ExportResource extends JaxRsResourceBase {
     @TimedResource
     @GET
     @Path("/{accountId:" + UUID_PATTERN + "}")
-    @Produces(TEXT_PLAIN)
-    @ApiOperation(value = "Export account data", response = String.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @Produces(APPLICATION_OCTET_STREAM)
+    @ApiOperation(value = "Export account data", response = Response.class)
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "Success"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public StreamingOutput exportDataForAccount(@PathParam("accountId") final UUID accountId,
                                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceItemResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceItemResource.java
index 3b94ad5..0c46744 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceItemResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceItemResource.java
@@ -53,6 +53,7 @@ import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.api.TagDefinitionApiException;
 import org.killbill.billing.util.api.TagUserApi;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
 
@@ -80,7 +81,7 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @GET
     @Path("/{invoiceItemId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve invoice item custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve invoice item custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getInvoiceItemCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -93,15 +94,16 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Path("/{invoiceItemId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to invoice item", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
+    public Response createInvoiceItemCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  final List<CustomFieldJson> customFields,
+                                                  @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 HttpServletRequest request,
+                                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -113,13 +115,14 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
+    public Response modifyInvoiceItemCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  final List<CustomFieldJson> customFields,
+                                                  @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -131,13 +134,14 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
+    public Response deleteInvoiceItemCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                                  @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -146,13 +150,13 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @GET
     @Path("/{invoiceItemId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve invoice item tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve invoice item tags", response = TagJson.class, responseContainer = "List", nickname = "getInvoiceItemTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID id,
                             @ApiParam(required=true) @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, AccountApiException {
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
@@ -165,15 +169,16 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Path("/{invoiceItemId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to invoice item", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
+    public Response createInvoiceItemTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                          final List<UUID> tagList,
+                                          @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,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -184,13 +189,14 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
+    public Response deleteInvoiceItemTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                          @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                          @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index c75b4e5..8632ec0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -72,11 +72,11 @@ import org.killbill.billing.util.api.TagUserApi;
 import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
 
 import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
@@ -146,11 +146,12 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + REFUNDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Refund a payment, and adjust the invoice if needed")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
+    @ApiOperation(value = "Refund a payment, and adjust the invoice if needed", response = InvoicePaymentJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created refund successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found")})
-    public Response createRefundWithAdjustments(final InvoicePaymentTransactionJson json,
-                                                @PathParam("paymentId") final UUID paymentId,
+    public Response createRefundWithAdjustments(@PathParam("paymentId") final UUID paymentId,
+                                                final InvoicePaymentTransactionJson json,
                                                 @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                                 @QueryParam(QUERY_PAYMENT_METHOD_ID) final UUID paymentMethodId,
                                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -209,11 +210,12 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACKS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargeback")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
+    @ApiOperation(value = "Record a chargeback", response = InvoicePaymentJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created chargeback successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found")})
-    public Response createChargeback(final InvoicePaymentTransactionJson json,
-                                     @PathParam("paymentId") final UUID paymentId,
+    public Response createChargeback(@PathParam("paymentId") final UUID paymentId,
+                                     final InvoicePaymentTransactionJson json,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
                                      @HeaderParam(HDR_COMMENT) final String comment,
@@ -237,11 +239,12 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACK_REVERSALS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargebackReversal")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
+    @ApiOperation(value = "Record a chargebackReversal", response = InvoicePaymentJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created chargeback reversal successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found")})
-    public Response createChargebackReversal(final InvoicePaymentTransactionJson json,
-                                             @PathParam("paymentId") final UUID paymentId,
+    public Response createChargebackReversal(@PathParam("paymentId") final UUID paymentId,
+                                             final InvoicePaymentTransactionJson json,
                                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                              @HeaderParam(HDR_REASON) final String reason,
                                              @HeaderParam(HDR_COMMENT) final String comment,
@@ -265,7 +268,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Complete an existing transaction")
-    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -273,15 +276,15 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response completeInvoicePaymentTransaction(final PaymentTransactionJson json,
-                                        @PathParam("paymentId") final UUID paymentId,
-                                        @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
-                                        @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                        @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,
-                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+    public Response completeInvoicePaymentTransaction(@PathParam("paymentId") final UUID paymentId,
+                                                      final PaymentTransactionJson json,
+                                                      @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
+                                                      @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                                      @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,
+                                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
 
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
@@ -307,7 +310,8 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         controlPluginNames.add("__INVOICE_PAYMENT_CONTROL_PLUGIN__");
         controlPluginNames.addAll(paymentControlPluginNames);
 
-        return completeTransactionInternal(json, payment, controlPluginNames, pluginProperties, tenantContext, createdBy, reason, comment, uriInfo, request);
+        completeTransactionInternal(json, payment, controlPluginNames, pluginProperties, tenantContext, createdBy, reason, comment, uriInfo, request);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -315,7 +319,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @GET
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getInvoicePaymentCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -328,15 +332,16 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to payment", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response createInvoicePaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                     final List<CustomFieldJson> customFields,
+                                                     @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 HttpServletRequest request,
+                                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -348,13 +353,14 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response modifyInvoicePaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                     final List<CustomFieldJson> customFields,
+                                                     @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -366,13 +372,14 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response deleteInvoicePaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                     @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                                     @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -381,13 +388,13 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @GET
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment tags", response = TagJson.class, responseContainer = "List", nickname = "getInvoicePaymentTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Payment not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -400,15 +407,16 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to payment", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response createInvoicePaymentTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                             final List<UUID> tagList,
+                                             @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,
+                                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -419,13 +427,14 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response deleteInvoicePaymentTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                             @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                             @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 7ca3659..2a37784 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -60,9 +60,7 @@ import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.ProductCategory;
@@ -101,6 +99,7 @@ import org.killbill.billing.util.api.TagUserApi;
 import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
@@ -188,9 +187,10 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
     }
 
+
     @TimedResource
     @GET
-    @Path("/{invoiceNumber:" + NUMBER_PATTERN + "}/")
+    @Path("/byNumber/{invoiceNumber:" + NUMBER_PATTERN + "}/")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve an invoice by number", response = InvoiceJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
@@ -293,7 +293,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Trigger an invoice generation", response = InvoiceJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created invoice successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
     public Response createFutureInvoice(@ApiParam(required=true) @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
                                         @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -323,9 +324,10 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Create a migration invoice", response = InvoiceJson.class, tags="Invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
-    public Response createMigrationInvoice(final List<InvoiceItemJson> items,
-                                           @PathParam("accountId") final UUID accountId,
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created migration invoice successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
+    public Response createMigrationInvoice(@PathParam("accountId") final UUID accountId,
+                                           final List<InvoiceItemJson> items,
                                            @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                            @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                            @HeaderParam(HDR_REASON) final String reason,
@@ -347,7 +349,9 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Generate a dryRun invoice", response = InvoiceJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
+    @ApiResponses(value = {/* @ApiResponse(code = 200, message = "Successful"),  */ /* Already added by default */
+                           @ApiResponse(code = 204, message = "Nothing to generate"),
+                           @ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
     public Response generateDryRunInvoice(@Nullable final InvoiceDryRunJson dryRunSubscriptionSpec,
                                           @ApiParam(required=true) @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
                                           @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate,
@@ -398,7 +402,7 @@ public class InvoiceResource extends JaxRsResourceBase {
             return Response.status(Status.OK).entity(new InvoiceJson(generatedInvoice, true, null, null)).build();
         } catch (InvoiceApiException e) {
             if (e.getCode() == ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
-                return Response.status(Status.NOT_FOUND).build();
+                return Response.status(Status.NO_CONTENT).build();
             }
             throw e;
         }
@@ -410,7 +414,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Delete a CBA item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
                            @ApiResponse(code = 404, message = "Account or invoice not found")})
     public Response deleteCBA(@PathParam("invoiceId") final UUID invoiceId,
                               @PathParam("invoiceItemId") final UUID invoiceItemId,
@@ -425,7 +430,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         invoiceApi.deleteCBA(account.getId(), invoiceId, invoiceItemId, callContext);
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -433,11 +438,12 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path("/{invoiceId:" + UUID_PATTERN + "}")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Adjust an invoice item")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
+    @ApiOperation(value = "Adjust an invoice item", response = InvoiceJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created adjustment Successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
-    public Response adjustInvoiceItem(final InvoiceItemJson json,
-                                      @PathParam("invoiceId") final UUID invoiceId,
+    public Response adjustInvoiceItem(@PathParam("invoiceId") final UUID invoiceId,
+                                      final InvoiceItemJson json,
                                       @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
@@ -467,7 +473,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                                                     json.getInvoiceItemId(),
                                                                     requestedDate,
                                                                     json.getAmount(),
-                                                                    Currency.valueOf(json.getCurrency()),
+                                                                    json.getCurrency(),
                                                                     json.getDescription(),
                                                                     json.getItemDetails(),
                                                                     callContext);
@@ -486,10 +492,11 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Path("/" + CHARGES + "/{accountId:" + UUID_PATTERN + "}")
     @ApiOperation(value = "Create external charge(s)", response = InvoiceItemJson.class, responseContainer = "List")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created external charge Successfully"),
+                           @ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response createExternalCharges(final List<InvoiceItemJson> externalChargesJson,
-                                          @PathParam("accountId") final UUID accountId,
+    public Response createExternalCharges(@PathParam("accountId") final UUID accountId,
+                                          final List<InvoiceItemJson> externalChargesJson,
                                           @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                           @QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -551,14 +558,14 @@ public class InvoiceResource extends JaxRsResourceBase {
                 @Override
                 public InvoiceItemJson apply(final InvoiceItemJson input) {
                     if (input.getCurrency() != null) {
-                        if (!input.getCurrency().equals(accountCurrency.name())) {
+                        if (!input.getCurrency().equals(accountCurrency)) {
                             throw new IllegalArgumentException(input.getCurrency().toString());
                         }
                         return input;
                     } else {
                         return new InvoiceItemJson(null,
                                                    input.getInvoiceId(),
-                                                   null,
+                                                   input.getLinkedInvoiceItemId(),
                                                    input.getAccountId(),
                                                    input.getChildAccountId(),
                                                    input.getBundleId(),
@@ -577,7 +584,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                                    input.getEndDate(),
                                                    input.getAmount(),
                                                    input.getRate(),
-                                                   accountCurrency.name(),
+                                                   accountCurrency,
                                                    input.getQuantity(),
                                                    input.getItemDetails(),
                                                    null,
@@ -604,11 +611,11 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve payments associated with an invoice", response = InvoicePaymentJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
-    public Response getPayments(@PathParam("invoiceId") final UUID invoiceId,
-                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
-                                @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
-                                @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, InvoiceApiException {
+    public Response getPaymentsForInvoice(@PathParam("invoiceId") final UUID invoiceId,
+                                          @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                          @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
+                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, InvoiceApiException {
 
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
@@ -644,11 +651,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Consumes(APPLICATION_JSON)
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
-    @ApiOperation(value = "Trigger a payment for invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or invoice id supplied"),
+    @ApiOperation(value = "Trigger a payment for invoice", response = InvoicePaymentJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Created payment Successfully"),
+                           @ApiResponse(code = 204, message = "Nothing to pay for"),
+                           @ApiResponse(code = 400, message = "Invalid account id or invoice id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response createInstantPayment(final InvoicePaymentJson payment,
-                                         @PathParam("invoiceId") final UUID invoiceId,
+    public Response createInstantPayment(@PathParam("invoiceId") final UUID invoiceId,
+                                         final InvoicePaymentJson payment,
                                          @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -680,7 +689,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @GET
     @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
     @Produces(TEXT_PLAIN)
-    @ApiOperation(value = "Retrieves the invoice translation for the tenant", response = String.class, hidden = true)
+    @ApiOperation(value = "Retrieves the invoice translation for the tenant", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
                            @ApiResponse(code = 404, message = "Translation not found")})
     public Response getInvoiceTranslation(@PathParam("locale") final String localeStr,
@@ -693,10 +702,10 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(TEXT_PLAIN)
     @Consumes(TEXT_PLAIN)
     @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
-    @ApiOperation(value = "Upload the invoice translation for the tenant")
-    @ApiResponses(value = {})
-    public Response uploadInvoiceTranslation(final String invoiceTranslation,
-                                             @PathParam("locale") final String localeStr,
+    @ApiOperation(value = "Upload the invoice translation for the tenant", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Uploaded invoice translation Successfully")})
+    public Response uploadInvoiceTranslation(@PathParam("locale") final String localeStr,
+                                             final String invoiceTranslation,
                                              @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                              @HeaderParam(HDR_REASON) final String reason,
@@ -719,7 +728,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @GET
     @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
     @Produces(TEXT_PLAIN)
-    @ApiOperation(value = "Retrieves the catalog translation for the tenant", response = String.class, hidden = true)
+    @ApiOperation(value = "Retrieves the catalog translation for the tenant", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
                            @ApiResponse(code = 404, message = "Template not found")})
     public Response getCatalogTranslation(@PathParam("locale") final String localeStr,
@@ -732,10 +741,10 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(TEXT_PLAIN)
     @Consumes(TEXT_PLAIN)
     @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
-    @ApiOperation(value = "Upload the catalog translation for the tenant")
-    @ApiResponses(value = {})
-    public Response uploadCatalogTranslation(final String catalogTranslation,
-                                             @PathParam("locale") final String localeStr,
+    @ApiOperation(value = "Upload the catalog translation for the tenant", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Uploaded catalog translation Successfully")})
+    public Response uploadCatalogTranslation(@PathParam("locale") final String localeStr,
+                                             final String catalogTranslation,
                                              @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                              @HeaderParam(HDR_REASON) final String reason,
@@ -759,7 +768,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @GET
     @Path("/" + INVOICE_TEMPLATE)
     @Produces(TEXT_HTML)
-    @ApiOperation(value = "Retrieves the invoice template for the tenant", response = String.class, hidden = true)
+    @ApiOperation(value = "Retrieves the invoice template for the tenant", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
     public Response getInvoiceTemplate(@javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
         return getTemplateResource(null, TenantKey.INVOICE_TEMPLATE, request);
@@ -770,8 +779,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(TEXT_HTML)
     @Consumes(TEXT_HTML)
     @Path("/" + INVOICE_TEMPLATE)
-    @ApiOperation(value = "Upload the invoice template for the tenant")
-    @ApiResponses(value = {})
+    @ApiOperation(value = "Upload the invoice template for the tenant", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Uploaded invoice template Successfully")})
     public Response uploadInvoiceTemplate(final String catalogTranslation,
                                           @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -791,11 +800,12 @@ public class InvoiceResource extends JaxRsResourceBase {
                                       uriInfo);
     }
 
+
     @TimedResource
     @GET
-    @Path("/" + INVOICE_MP_TEMPLATE)
+    @Path("/" + INVOICE_MP_TEMPLATE + "/{locale:" + ANYTHING_PATTERN + "}/")
     @Produces(TEXT_HTML)
-    @ApiOperation(value = "Retrieves the manualPay invoice template for the tenant", response = String.class, hidden = true)
+    @ApiOperation(value = "Retrieves the manualPay invoice template for the tenant", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
     public Response getInvoiceMPTemplate(@PathParam("locale") final String localeStr,
                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
@@ -807,8 +817,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(TEXT_HTML)
     @Consumes(TEXT_HTML)
     @Path("/" + INVOICE_MP_TEMPLATE)
-    @ApiOperation(value = "Upload the manualPay invoice template for the tenant")
-    @ApiResponses(value = {})
+    @ApiOperation(value = "Upload the manualPay invoice template for the tenant", response = String.class)
     public Response uploadInvoiceMPTemplate(final String catalogTranslation,
                                             @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -877,7 +886,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @GET
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve invoice custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve invoice custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getInvoiceCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -890,15 +899,16 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to invoice", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied")})
+    public Response createInvoiceCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request,
+                                              @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -910,13 +920,14 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied")})
+    public Response modifyInvoiceCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -927,13 +938,14 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied")})
+    public Response deleteInvoiceCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -942,12 +954,12 @@ public class InvoiceResource extends JaxRsResourceBase {
     @GET
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve invoice tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve invoice tags", response = TagJson.class, responseContainer = "List", nickname = "getInvoiceTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID invoiceId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, InvoiceApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
@@ -959,15 +971,16 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to invoice", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied")})
+    public Response createInvoiceTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                      final List<UUID> tagList,
+                                      @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,
+                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -978,13 +991,14 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied")})
+    public Response deleteInvoiceTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                      @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                      @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -995,7 +1009,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Perform the invoice status transition from DRAFT to COMMITTED")
-    @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 404, message = "Invoice not found")})
     public Response commitInvoice(@PathParam("invoiceId") final UUID invoiceId,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
@@ -1005,7 +1020,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         invoiceApi.commitInvoice(invoiceId, callContext);
-        return Response.status(Response.Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -1014,7 +1029,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Perform the action of voiding an invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
     public Response voidInvoice(@PathParam("invoiceId") final UUID invoiceId,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -1025,7 +1041,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         invoiceApi.voidInvoice(invoiceId, callContext);
-        return Response.status(Response.Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @Override
@@ -1055,19 +1071,19 @@ public class InvoiceResource extends JaxRsResourceBase {
                 this.billingPolicy = null;
                 this.overrides = null;
             } else {
-                this.dryRunType = input.getDryRunType() != null ? DryRunType.valueOf(input.getDryRunType()) : DryRunType.TARGET_DATE;
-                this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
+                this.dryRunType = input.getDryRunType() != null ? input.getDryRunType() : DryRunType.TARGET_DATE;
+                this.action = input.getDryRunAction() != null ? input.getDryRunAction() : null;
                 this.subscriptionId = input.getSubscriptionId();
                 this.bundleId = input.getBundleId();
                 this.effectiveDate = input.getEffectiveDate();
-                this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
+                this.billingPolicy = input.getBillingPolicy() != null ? input.getBillingPolicy() : null;
                 final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
                                                                input.getProductCategory() != null &&
                                                                input.getBillingPeriod() != null) ?
                                                               new PlanPhaseSpecifier(input.getProductName(),
-                                                                                     BillingPeriod.valueOf(input.getBillingPeriod()),
+                                                                                     input.getBillingPeriod(),
                                                                                      input.getPriceListName(),
-                                                                                     input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null) :
+                                                                                     input.getPhaseType() != null ? input.getPhaseType() : null) :
                                                               null;
                 this.specifier = planPhaseSpecifier;
                 this.overrides = input.getPriceOverrides() != null ?
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 409b58b..6434696 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -20,288 +20,279 @@ package org.killbill.billing.jaxrs.resources;
 
 public interface JaxrsResource {
 
-    public static final String API_PREFIX = "";
-    public static final String API_VERSION = "/1.0";
-    public static final String API_POSTFIX = "/kb";
+    String API_PREFIX = "";
+    String API_VERSION = "/1.0";
+    String API_POSTFIX = "/kb";
 
-    public static final String PREFIX = API_PREFIX + API_VERSION + API_POSTFIX;
+    String PREFIX = API_PREFIX + API_VERSION + API_POSTFIX;
 
-    public static final String TIMELINE = "timeline";
-    public static final String REGISTER_NOTIFICATION_CALLBACK = "registerNotificationCallback";
-    public static final String UPLOAD_PLUGIN_CONFIG = "uploadPluginConfig";
-    public static final String UPLOAD_PER_TENANT_CONFIG = "uploadPerTenantConfig";
-    public static final String UPLOAD_PLUGIN_PAYMENT_STATE_MACHINE_CONFIG = "uploadPluginPaymentStateMachineConfig";
-    public static final String USER_KEY_VALUE = "userKeyValue";
-    public static final String SEARCH = "search";
-
-    public static final String PLUGIN_CONFIG = "pluginConfig";
+    String TIMELINE = "timeline";
+    String REGISTER_NOTIFICATION_CALLBACK = "registerNotificationCallback";
+    String UPLOAD_PLUGIN_CONFIG = "uploadPluginConfig";
+    String UPLOAD_PER_TENANT_CONFIG = "uploadPerTenantConfig";
+    String UPLOAD_PLUGIN_PAYMENT_STATE_MACHINE_CONFIG = "uploadPluginPaymentStateMachineConfig";
+    String USER_KEY_VALUE = "userKeyValue";
+    String SEARCH = "search";
 
     /*
      * Multi-Tenancy headers
      */
-    public static String HDR_API_KEY = "X-Killbill-ApiKey";
-    public static String HDR_API_SECRET = "X-Killbill-ApiSecret";
+    String HDR_API_KEY = "X-Killbill-ApiKey";
+    String HDR_API_SECRET = "X-Killbill-ApiSecret";
 
     /*
      * Metadata Additional headers
      */
-    public static String HDR_CREATED_BY = "X-Killbill-CreatedBy";
-    public static String HDR_REASON = "X-Killbill-Reason";
-    public static String HDR_COMMENT = "X-Killbill-Comment";
-    public static String HDR_PAGINATION_CURRENT_OFFSET = "X-Killbill-Pagination-CurrentOffset";
-    public static String HDR_PAGINATION_NEXT_OFFSET = "X-Killbill-Pagination-NextOffset";
-    public static String HDR_PAGINATION_TOTAL_NB_RECORDS = "X-Killbill-Pagination-TotalNbRecords";
-    public static String HDR_PAGINATION_MAX_NB_RECORDS = "X-Killbill-Pagination-MaxNbRecords";
-    public static String HDR_PAGINATION_NEXT_PAGE_URI = "X-Killbill-Pagination-NextPageUri";
+    String HDR_CREATED_BY = "X-Killbill-CreatedBy";
+    String HDR_REASON = "X-Killbill-Reason";
+    String HDR_COMMENT = "X-Killbill-Comment";
+    String HDR_PAGINATION_CURRENT_OFFSET = "X-Killbill-Pagination-CurrentOffset";
+    String HDR_PAGINATION_NEXT_OFFSET = "X-Killbill-Pagination-NextOffset";
+    String HDR_PAGINATION_TOTAL_NB_RECORDS = "X-Killbill-Pagination-TotalNbRecords";
+    String HDR_PAGINATION_MAX_NB_RECORDS = "X-Killbill-Pagination-MaxNbRecords";
+    String HDR_PAGINATION_NEXT_PAGE_URI = "X-Killbill-Pagination-NextPageUri";
 
     /*
      * Patterns
      */
-    public static String STRING_PATTERN = "\\w+";
-    public static String UUID_PATTERN = "\\w+-\\w+-\\w+-\\w+-\\w+";
-    public static String NUMBER_PATTERN = "[0-9]+";
-    public static String ANYTHING_PATTERN = ".*";
+    String STRING_PATTERN = "\\w+";
+    String UUID_PATTERN = "\\w+-\\w+-\\w+-\\w+-\\w+";
+    String NUMBER_PATTERN = "[0-9]+";
+    String ANYTHING_PATTERN = ".*";
+
+    String PATH_PAYMENT_PLUGIN_NAME = "pluginName";
 
     /*
      * Query parameters
      */
+    String QUERY_LOCAL_NODE_ONLY = "localNodeOnly";
+    String QUERY_EXTERNAL_KEY = "externalKey";
+    String QUERY_API_KEY = "apiKey";
+    String QUERY_REQUESTED_DT = "requestedDate";
+    String QUERY_PAYMENT_EXTERNAL_KEY = "paymentExternalKey";
+    String QUERY_TRANSACTION_EXTERNAL_KEY = "transactionExternalKey";
+    String QUERY_ENTITLEMENT_REQUESTED_DT = "entitlementDate";
+    String QUERY_BILLING_REQUESTED_DT = "billingDate";
+    String QUERY_CALL_COMPLETION = "callCompletion";
+    String QUERY_USE_REQUESTED_DATE_FOR_BILLING = "useRequestedDateForBilling";
+    String QUERY_CALL_TIMEOUT = "callTimeoutSec";
+    String QUERY_TARGET_DATE = "targetDate";
+    String QUERY_BILLING_POLICY = "billingPolicy";
+    String QUERY_MIGRATED = "migrated";
+    String QUERY_ENTITLEMENT_POLICY = "entitlementPolicy";
+    String QUERY_SEARCH_OFFSET = "offset";
+    String QUERY_SEARCH_LIMIT = "limit";
+    String QUERY_ENTITLEMENT_EFFECTIVE_FROM_DT = "effectiveFromDate";
+    String QUERY_FORCE_NEW_BCD_WITH_PAST_EFFECTIVE_DATE = "forceNewBcdWithPastEffectiveDate";
 
+    String QUERY_ACCOUNT_WITH_BALANCE = "accountWithBalance";
+    String QUERY_ACCOUNT_WITH_BALANCE_AND_CBA = "accountWithBalanceAndCBA";
+    String QUERY_ACCOUNT_TREAT_NULL_AS_RESET = "treatNullAsReset";
 
-    public static final String QUERY_LOCAL_NODE_ONLY = "localNodeOnly";
-    public static final String QUERY_EXTERNAL_KEY = "externalKey";
-    public static final String QUERY_API_KEY = "apiKey";
-    public static final String QUERY_REQUESTED_DT = "requestedDate";
-    public static final String QUERY_PAYMENT_EXTERNAL_KEY = "paymentExternalKey";
-    public static final String QUERY_TRANSACTION_EXTERNAL_KEY = "transactionExternalKey";
-    public static final String QUERY_ENTITLEMENT_REQUESTED_DT = "entitlementDate";
-    public static final String QUERY_BILLING_REQUESTED_DT = "billingDate";
-    public static final String QUERY_CALL_COMPLETION = "callCompletion";
-    public static final String QUERY_USE_REQUESTED_DATE_FOR_BILLING = "useRequestedDateForBilling";
-    public static final String QUERY_CALL_TIMEOUT = "callTimeoutSec";
-    public static final String QUERY_TARGET_DATE = "targetDate";
-    public static final String QUERY_BILLING_POLICY = "billingPolicy";
-    public static final String QUERY_MIGRATED = "migrated";
-    public static final String QUERY_ENTITLEMENT_POLICY = "entitlementPolicy";
-    public static final String QUERY_SEARCH_OFFSET = "offset";
-    public static final String QUERY_SEARCH_LIMIT = "limit";
-    public static final String QUERY_ENTITLEMENT_EFFECTIVE_FROM_DT = "effectiveFromDate";
-    public static final String QUERY_FORCE_NEW_BCD_WITH_PAST_EFFECTIVE_DATE = "forceNewBcdWithPastEffectiveDate";
-
-    public static final String QUERY_ACCOUNT_WITH_BALANCE = "accountWithBalance";
-    public static final String QUERY_ACCOUNT_WITH_BALANCE_AND_CBA = "accountWithBalanceAndCBA";
-    public static final String QUERY_ACCOUNT_TREAT_NULL_AS_RESET = "treatNullAsReset";
-
-    public static final String QUERY_ACCOUNT_ID = "accountId";
-
-    public static final String QUERY_CANCEL_ALL_SUBSCRIPTIONS = "cancelAllSubscriptions";
-    public static final String QUERY_WRITE_OFF_UNPAID_INVOICES = "writeOffUnpaidInvoices";
-    public static final String QUERY_ITEM_ADJUST_UNPAID_INVOICES = "itemAdjustUnpaidInvoices";
-    public static final String QUERY_REMOVE_FUTURE_NOTIFICATIONS = "removeFutureNotifications";
+    String QUERY_ACCOUNT_ID = "accountId";
 
-    public static final String QUERY_BLOCKING_STATE_TYPES = "blockingStateTypes";
-    public static final String QUERY_BLOCKING_STATE_SVCS = "blockingStateSvcs";
+    String QUERY_CANCEL_ALL_SUBSCRIPTIONS = "cancelAllSubscriptions";
+    String QUERY_WRITE_OFF_UNPAID_INVOICES = "writeOffUnpaidInvoices";
+    String QUERY_ITEM_ADJUST_UNPAID_INVOICES = "itemAdjustUnpaidInvoices";
+    String QUERY_REMOVE_FUTURE_NOTIFICATIONS = "removeFutureNotifications";
 
+    String QUERY_BLOCKING_STATE_TYPES = "blockingStateTypes";
+    String QUERY_BLOCKING_STATE_SVCS = "blockingStateSvcs";
 
-    public static final String QUERY_INVOICE_WITH_ITEMS = "withItems";
-    public static final String QUERY_WITH_MIGRATION_INVOICES = "withMigrationInvoices";
-    public static final String QUERY_UNPAID_INVOICES_ONLY = "unpaidInvoicesOnly";
-    public static final String QUERY_INCLUDE_VOIDED_INVOICES = "includeVoidedInvoices";
-    public static final String QUERY_INVOICE_WITH_CHILDREN_ITEMS = "withChildrenItems";
+    String QUERY_INVOICE_WITH_ITEMS = "withItems";
+    String QUERY_WITH_MIGRATION_INVOICES = "withMigrationInvoices";
+    String QUERY_UNPAID_INVOICES_ONLY = "unpaidInvoicesOnly";
+    String QUERY_INCLUDE_VOIDED_INVOICES = "includeVoidedInvoices";
+    String QUERY_INVOICE_WITH_CHILDREN_ITEMS = "withChildrenItems";
 
-    public static final String QUERY_PAYMENT_EXTERNAL = "externalPayment";
-    public static final String QUERY_PAYMENT_AMOUNT = "paymentAmount";
-    public static final String QUERY_PAYMENT_WITH_REFUNDS_AND_CHARGEBACKS = "withRefundsAndChargebacks";
-    public static final String QUERY_PAYMENT_PLUGIN_NAME = "pluginName";
-    public static final String QUERY_PAYMENT_METHOD_ID = "paymentMethodId";
-    public static final String QUERY_PAYMENT_CONTROL_PLUGIN_NAME = "controlPluginName";
+    String QUERY_PAYMENT_EXTERNAL = "externalPayment";
+    String QUERY_PAYMENT_AMOUNT = "paymentAmount";
+    String QUERY_PAYMENT_WITH_REFUNDS_AND_CHARGEBACKS = "withRefundsAndChargebacks";
+    String QUERY_PAYMENT_PLUGIN_NAME = "pluginName";
+    String QUERY_PAYMENT_METHOD_ID = "paymentMethodId";
+    String QUERY_PAYMENT_CONTROL_PLUGIN_NAME = "controlPluginName";
 
-    public static final String QUERY_TENANT_USE_GLOBAL_DEFAULT = "useGlobalDefault";
-    public static final String QUERY_TAGS_INCLUDED_DELETED = "includedDeleted";
+    String QUERY_TENANT_USE_GLOBAL_DEFAULT = "useGlobalDefault";
+    String QUERY_TAGS_INCLUDED_DELETED = "includedDeleted";
 
-    public static final String QUERY_TAGS = "tagList";
-    public static final String QUERY_CUSTOM_FIELDS = "customFieldList";
+    String QUERY_TAG = "tagDef";
+    String QUERY_CUSTOM_FIELD = "customField";
 
-    public static final String QUERY_OBJECT_TYPE = "objectType";
+    String QUERY_OBJECT_TYPE = "objectType";
 
-    public static final String QUERY_PAYMENT_METHOD_PLUGIN_NAME = "pluginName";
-    public static final String QUERY_WITH_PLUGIN_INFO = "withPluginInfo";
-    public static final String QUERY_WITH_ATTEMPTS = "withAttempts";
-    public static final String QUERY_PAYMENT_METHOD_IS_DEFAULT = "isDefault";
+    String QUERY_PAYMENT_METHOD_PLUGIN_NAME = "pluginName";
+    String QUERY_WITH_PLUGIN_INFO = "withPluginInfo";
+    String QUERY_WITH_ATTEMPTS = "withAttempts";
+    String QUERY_PAYMENT_METHOD_IS_DEFAULT = "isDefault";
 
-    public static final String QUERY_PAY_ALL_UNPAID_INVOICES = "payAllUnpaidInvoices";
-    public static final String QUERY_PAY_INVOICE = "payInvoice";
+    String QUERY_PAY_ALL_UNPAID_INVOICES = "payAllUnpaidInvoices";
+    String QUERY_PAY_INVOICE = "payInvoice";
 
-    public static final String QUERY_PLUGIN_PROPERTY = "pluginProperty";
+    String QUERY_PLUGIN_PROPERTY = "pluginProperty";
 
-    public static final String QUERY_START_DATE = "startDate";
-    public static final String QUERY_END_DATE = "endDate";
+    String QUERY_START_DATE = "startDate";
+    String QUERY_END_DATE = "endDate";
 
-    public static final String QUERY_DELETE_IF_EXISTS = "deleteIfExists";
+    String QUERY_DELETE_IF_EXISTS = "deleteIfExists";
 
-    public static final String QUERY_BUNDLE_TRANSFER_ADDON = "transferAddOn";
-    public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
-    public static final String QUERY_BUNDLES_FILTER = "bundlesFilter";
+    String QUERY_BUNDLES_FILTER = "bundlesFilter";
 
-    public static final String QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED = "renameKeyIfExistsAndUnused";
+    String QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED = "renameKeyIfExistsAndUnused";
 
-    public static final String QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF = "deleteDefaultPmWithAutoPayOff";
+    String QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF = "deleteDefaultPmWithAutoPayOff";
 
-    public static final String QUERY_FORCE_DEFAULT_PM_DELETION = "forceDefaultPmDeletion";
+    String QUERY_FORCE_DEFAULT_PM_DELETION = "forceDefaultPmDeletion";
 
-    public static final String QUERY_AUDIT = "audit";
+    String QUERY_AUDIT = "audit";
 
-    public static final String QUERY_BCD = "bcd";
+    String QUERY_BCD = "bcd";
 
-    public static final String QUERY_PARALLEL = "parallel";
+    String QUERY_PARALLEL = "parallel";
 
-    public static final String QUERY_AUTO_COMMIT = "autoCommit";
+    String QUERY_AUTO_COMMIT = "autoCommit";
 
-    public static final String QUERY_NOTIFICATION_CALLBACK = "cb";
+    String QUERY_NOTIFICATION_CALLBACK = "cb";
 
-    public static final String PAGINATION = "pagination";
+    String PAGINATION = "pagination";
 
-    public static final String ADMIN = "admin";
-    public static final String ADMIN_PATH = PREFIX + "/" + ADMIN;
+    String ADMIN = "admin";
+    String ADMIN_PATH = PREFIX + "/" + ADMIN;
 
-    public static final String ACCOUNTS = "accounts";
-    public static final String ACCOUNTS_PATH = PREFIX + "/" + ACCOUNTS;
+    String ACCOUNTS = "accounts";
+    String ACCOUNTS_PATH = PREFIX + "/" + ACCOUNTS;
 
-    public static final String ANALYTICS = "analytics";
-    public static final String ANALYTICS_PATH = PREFIX + "/" + ANALYTICS;
+    String ANALYTICS = "analytics";
+    String ANALYTICS_PATH = PREFIX + "/" + ANALYTICS;
 
-    public static final String BUNDLES = "bundles";
-    public static final String BUNDLES_PATH = PREFIX + "/" + BUNDLES;
+    String BUNDLES = "bundles";
+    String BUNDLES_PATH = PREFIX + "/" + BUNDLES;
 
-    public static final String SECURITY = "security";
-    public static final String SECURITY_PATH = PREFIX + "/" + SECURITY;
+    String SECURITY = "security";
+    String SECURITY_PATH = PREFIX + "/" + SECURITY;
 
-    public static final String SUBSCRIPTIONS = "subscriptions";
-    public static final String SUBSCRIPTIONS_PATH = PREFIX + "/" + SUBSCRIPTIONS;
+    String SUBSCRIPTIONS = "subscriptions";
+    String SUBSCRIPTIONS_PATH = PREFIX + "/" + SUBSCRIPTIONS;
 
-    public static final String ENTITLEMENTS = "entitlements";
-    public static final String ENTITLEMENTS_PATH = PREFIX + "/" + ENTITLEMENTS;
+    String ENTITLEMENTS = "entitlements";
+    String ENTITLEMENTS_PATH = PREFIX + "/" + ENTITLEMENTS;
 
-    public static final String TAG_DEFINITIONS = "tagDefinitions";
-    public static final String TAG_DEFINITIONS_PATH = PREFIX + "/" + TAG_DEFINITIONS;
+    String TAG_DEFINITIONS = "tagDefinitions";
+    String TAG_DEFINITIONS_PATH = PREFIX + "/" + TAG_DEFINITIONS;
 
-    public static final String INVOICES = "invoices";
-    public static final String INVOICES_PATH = PREFIX + "/" + INVOICES;
+    String INVOICES = "invoices";
+    String INVOICES_PATH = PREFIX + "/" + INVOICES;
 
-    public static final String INVOICE_ITEMS = "invoiceItems";
-    public static final String INVOICES_ITEMS_PATH = PREFIX + "/" + INVOICE_ITEMS;
+    String INVOICE_ITEMS = "invoiceItems";
+    String INVOICES_ITEMS_PATH = PREFIX + "/" + INVOICE_ITEMS;
 
-    public static final String CHARGES = "charges";
-    public static final String CHARGES_PATH = PREFIX + "/" + INVOICES + "/" + CHARGES;
+    String CHARGES = "charges";
+    String CHARGES_PATH = PREFIX + "/" + INVOICES + "/" + CHARGES;
 
-    public static final String ATTEMPTS = "attempts";
-    public static final String PAYMENTS = "payments";
-    public static final String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;
+    String PAYMENTS = "payments";
+    String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;
 
-    public static final String PAYMENT_TRANSACTIONS = "paymentTransactions";
-    public static final String PAYMENT_TRANSACTIONS_PATH = PREFIX + "/" + PAYMENT_TRANSACTIONS;
+    String PAYMENT_TRANSACTIONS = "paymentTransactions";
+    String PAYMENT_TRANSACTIONS_PATH = PREFIX + "/" + PAYMENT_TRANSACTIONS;
+    String ATTEMPTS = "attempts";
 
-    public static final String PAYMENT_GATEWAYS = "paymentGateways";
-    public static final String PAYMENT_GATEWAYS_PATH = PREFIX + "/" + PAYMENT_GATEWAYS;
+    String PAYMENT_GATEWAYS = "paymentGateways";
+    String PAYMENT_GATEWAYS_PATH = PREFIX + "/" + PAYMENT_GATEWAYS;
 
-    public static final String REFUNDS = "refunds";
+    String REFUNDS = "refunds";
 
-    public static final String PAYMENT_METHODS = "paymentMethods";
-    public static final String PAYMENT_METHODS_PATH = PREFIX + "/" + PAYMENT_METHODS;
-    public static final String PAYMENT_METHODS_DEFAULT_PATH_POSTFIX = "setDefault";
+    String PAYMENT_METHODS = "paymentMethods";
+    String PAYMENT_METHODS_PATH = PREFIX + "/" + PAYMENT_METHODS;
+    String PAYMENT_METHODS_DEFAULT_PATH_POSTFIX = "setDefault";
 
-    public static final String CREDITS = "credits";
-    public static final String CREDITS_PATH = PREFIX + "/" + CREDITS;
+    String CREDITS = "credits";
+    String CREDITS_PATH = PREFIX + "/" + CREDITS;
 
-    public static final String INVOICE_PAYMENTS = "invoicePayments";
-    public static final String INVOICE_PAYMENTS_PATH = PREFIX + "/" + INVOICE_PAYMENTS;
-    public static final String DRY_RUN = "dryRun";
+    String INVOICE_PAYMENTS = "invoicePayments";
+    String INVOICE_PAYMENTS_PATH = PREFIX + "/" + INVOICE_PAYMENTS;
+    String DRY_RUN = "dryRun";
 
-    public static final String CHARGEBACKS = "chargebacks";
-    public static final String CHARGEBACKS_PATH = PREFIX + "/" + CHARGEBACKS;
+    String CHARGEBACKS = "chargebacks";
+    String CHARGEBACKS_PATH = PREFIX + "/" + CHARGEBACKS;
 
-    public static final String CHARGEBACK_REVERSALS = "chargebackReversals";
-    public static final String CHARGEBACK_REVERSALS_PATH = PREFIX + "/" + CHARGEBACK_REVERSALS;
+    String CHARGEBACK_REVERSALS = "chargebackReversals";
+    String CHARGEBACK_REVERSALS_PATH = PREFIX + "/" + CHARGEBACK_REVERSALS;
 
-    public static final String ALL_TAGS = "allTags";
-    public static final String TAGS = "tags";
-    public static final String TAGS_PATH = PREFIX + "/" + TAGS;
+    String ALL_TAGS = "allTags";
+    String TAGS = "tags";
+    String TAGS_PATH = PREFIX + "/" + TAGS;
 
-    public static final String ALL_CUSTOM_FIELDS = "allCustomFields";
-    public static final String CUSTOM_FIELDS = "customFields";
-    public static final String CUSTOM_FIELDS_PATH = PREFIX + "/" + CUSTOM_FIELDS;
+    String ALL_CUSTOM_FIELDS = "allCustomFields";
+    String CUSTOM_FIELDS = "customFields";
+    String CUSTOM_FIELDS_PATH = PREFIX + "/" + CUSTOM_FIELDS;
 
-    public static final String EMAILS = "emails";
-    public static final String EMAIL_NOTIFICATIONS = "emailNotifications";
+    String EMAILS = "emails";
+    String EMAIL_NOTIFICATIONS = "emailNotifications";
 
-    public static final String CATALOG = "catalog";
-    public static final String CATALOG_PATH = PREFIX + "/" + CATALOG;
+    String CATALOG = "catalog";
+    String CATALOG_PATH = PREFIX + "/" + CATALOG;
 
-    public static final String OVERDUE = "overdue";
-    public static final String OVERDUE_PATH = PREFIX + "/" + OVERDUE;
+    String OVERDUE = "overdue";
+    String OVERDUE_PATH = PREFIX + "/" + OVERDUE;
 
-    public static final String TENANTS = "tenants";
-    public static final String TENANTS_PATH = PREFIX + "/" + TENANTS;
+    String TENANTS = "tenants";
+    String TENANTS_PATH = PREFIX + "/" + TENANTS;
 
-    public static final String USAGES = "usages";
-    public static final String USAGES_PATH = PREFIX + "/" + USAGES;
+    String USAGES = "usages";
+    String USAGES_PATH = PREFIX + "/" + USAGES;
 
-    public static final String EXPORT = "export";
-    public static final String EXPORT_PATH = PREFIX + "/" + EXPORT;
+    String EXPORT = "export";
+    String EXPORT_PATH = PREFIX + "/" + EXPORT;
 
-    public static final String PLUGINS_INFO = "pluginsInfo";
-    public static final String PLUGINS_INFO_PATH = PREFIX + "/" + PLUGINS_INFO;
+    String PLUGINS_INFO = "pluginsInfo";
+    String PLUGINS_INFO_PATH = PREFIX + "/" + PLUGINS_INFO;
 
-    public static final String NODES_INFO = "nodesInfo";
-    public static final String NODES_INFO_PATH = PREFIX + "/" + NODES_INFO;
+    String NODES_INFO = "nodesInfo";
+    String NODES_INFO_PATH = PREFIX + "/" + NODES_INFO;
 
     // No PREFIX here!
-    public static final String PLUGINS = "plugins";
-    public static final String PLUGINS_PATH = "/" + PLUGINS;
-
-    public static final String TEST = "test";
-    public static final String TEST_PATH = PREFIX + "/" + TEST;
-
-    public static final String CBA_REBALANCING = "cbaRebalancing";
-
-
-    public static final String UNDO_CHANGE_PLAN = "undoChangePlan";
-    public static final String UNDO_CANCEL = "uncancel";
+    String PLUGINS = "plugins";
+    String PLUGINS_PATH = "/" + PLUGINS;
 
-    public static final String PAUSE = "pause";
-    public static final String RESUME = "resume";
-    public static final String BLOCK = "block";
-    public static final String RENAME_KEY = "renameKey";
+    String TEST = "test";
+    String TEST_PATH = PREFIX + "/" + TEST;
 
-    public static final String AUTHORIZATION = "authorization";
-    public static final String CAPTURE = "capture";
+    String CBA_REBALANCING = "cbaRebalancing";
 
-    public static final String HOSTED = "hosted";
-    public static final String FORM = "form";
-    public static final String NOTIFICATION = "notification";
+    String UNDO_CHANGE_PLAN = "undoChangePlan";
+    String UNDO_CANCEL = "uncancel";
 
-    public static final String CANCEL_SCHEDULED_PAYMENT_TRANSACTION = "cancelScheduledPaymentTransaction";
+    String PAUSE = "pause";
+    String RESUME = "resume";
+    String BLOCK = "block";
+    String RENAME_KEY = "renameKey";
 
+    String AUTHORIZATION = "authorization";
+    String CAPTURE = "capture";
 
-    public static final String INVOICE_TEMPLATE = "template";
-    public static final String INVOICE_MP_TEMPLATE = "manualPayTemplate";
-    public static final String INVOICE_TRANSLATION = "translation";
-    public static final String INVOICE_CATALOG_TRANSLATION = "catalogTranslation";
-    public static final String COMMIT_INVOICE = "commitInvoice";
-    public static final String VOID_INVOICE = "voidInvoice";
+    String HOSTED = "hosted";
+    String FORM = "form";
+    String NOTIFICATION = "notification";
 
-    public static final String COMBO = "combo";
-    public static final String MIGRATION = "migration";
+    String CANCEL_SCHEDULED_PAYMENT_TRANSACTION = "cancelScheduledPaymentTransaction";
 
-    public static final String CHILDREN = "children";
-    public static final String BCD = "bcd";
-    public static final String TRANSFER_CREDIT = "transferCredit";
+    String INVOICE_TEMPLATE = "template";
+    String INVOICE_MP_TEMPLATE = "manualPayTemplate";
+    String INVOICE_TRANSLATION = "translation";
+    String INVOICE_CATALOG_TRANSLATION = "catalogTranslation";
+    String COMMIT_INVOICE = "commitInvoice";
+    String VOID_INVOICE = "voidInvoice";
 
-    public static final String CACHE = "cache";
-    public static final String HEALTHCHECK = "healthcheck";
+    String COMBO = "combo";
+    String MIGRATION = "migration";
 
-    public static final String QUERY_INCLUDED_DELETED = "includedDeleted";
+    String CHILDREN = "children";
+    String BCD = "bcd";
+    String TRANSFER_CREDIT = "transferCredit";
 
-    public static final String AUDIT_LOG = "auditLogs";
-    public static final String AUDIT_LOG_WITH_HISTORY = "auditLogsWithHistory";
+    String CACHE = "cache";
+    String HEALTHCHECK = "healthcheck";
 
+    String QUERY_INCLUDED_DELETED = "includedDeleted";
+    String AUDIT_LOG = "auditLogs";
+    String AUDIT_LOG_WITH_HISTORY = "auditLogsWithHistory";
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index 78cecc1..87b2c37 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -18,7 +18,6 @@
 
 package org.killbill.billing.jaxrs.resources;
 
-import java.io.Closeable;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.math.BigDecimal;
@@ -114,6 +113,7 @@ import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
@@ -163,15 +163,17 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         return null;
     }
 
-    public Response addBlockingState(final BlockingStateJson json,
-                                     final UUID blockableId,
-                                     final BlockingStateType type,
-                                     final String requestedDate,
-                                     final List<String> pluginPropertiesString,
-                                     final String createdBy,
-                                     final String reason,
-                                     final String comment,
-                                     final HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
+    protected Response addBlockingState(final BlockingStateJson json,
+                                        final UUID accountId,
+                                        final UUID blockableId,
+                                        final BlockingStateType type,
+                                        final String requestedDate,
+                                        final List<String> pluginPropertiesString,
+                                        final String createdBy,
+                                        final String reason,
+                                        final String comment,
+                                        final HttpServletRequest request,
+                                        @Nullable final UriInfo uriInfo) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
@@ -183,7 +185,9 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         final LocalDate resolvedRequestedDate = toLocalDate(requestedDate);
         final BlockingState input = new DefaultBlockingState(blockableId, type, json.getStateName(), json.getService(), isBlockChange, isBlockEntitlement, isBlockBilling, null);
         subscriptionApi.addBlockingState(input, resolvedRequestedDate, pluginProperties, callContext);
-        return Response.status(Status.OK).build();
+        return uriInfo != null ?
+               uriBuilder.buildResponse(uriInfo, AccountResource.class, "getBlockingStates", accountId, ImmutableMap.<String, String>of(QUERY_BLOCKING_STATE_TYPES, type.name()) , request) :
+               null;
     }
 
     protected Response getTags(final UUID accountId, final UUID taggedObjectId, final AuditMode auditMode, final boolean includeDeleted, final TenantContext context) throws TagDefinitionApiException {
@@ -209,19 +213,17 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
     protected Response createTags(final UUID id,
-                                  final String tagList,
+                                  final List<UUID> tagList,
                                   final UriInfo uriInfo,
                                   final CallContext context,
                                   final HttpServletRequest request) throws TagApiException {
-        final Collection<UUID> input = getTagDefinitionUUIDs(tagList);
-        tagUserApi.addTags(id, getObjectType(), input, context);
+        tagUserApi.addTags(id, getObjectType(), tagList, context);
         // TODO This will always return 201, even if some (or all) tags already existed (in which case we don't do anything)
         return uriBuilder.buildResponse(uriInfo, this.getClass(), "getTags", id, request);
     }
 
-    protected Collection<UUID> getTagDefinitionUUIDs(final String tagList) {
-        final String[] tagParts = tagList.split(",\\s*");
-        return Collections2.transform(ImmutableList.copyOf(tagParts), new Function<String, UUID>() {
+    protected Collection<UUID> getTagDefinitionUUIDs(final List<String> tagList) {
+        return Collections2.transform(tagList, new Function<String, UUID>() {
             @Override
             public UUID apply(final String input) {
                 return UUID.fromString(input);
@@ -230,12 +232,10 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
     protected Response deleteTags(final UUID id,
-                                  final String tagList,
+                                  final List<UUID> tagList,
                                   final CallContext context) throws TagApiException {
-        final Collection<UUID> input = getTagDefinitionUUIDs(tagList);
-        tagUserApi.removeTags(id, getObjectType(), input, context);
-
-        return Response.status(Response.Status.OK).build();
+        tagUserApi.removeTags(id, getObjectType(), tagList, context);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     protected Response getCustomFields(final UUID id, final AuditMode auditMode, final TenantContext context) {
@@ -270,7 +270,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         return uriBuilder.buildResponse(uriInfo, this.getClass(), "getCustomFields", id, request);
     }
 
-
     protected Response modifyCustomFields(final UUID id,
                                           final List<CustomFieldJson> customFields,
                                           final CallContext context) throws CustomFieldApiException {
@@ -282,11 +281,9 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
 
         customFieldUserApi.updateCustomFields(input, context);
-        return Response.status(Response.Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
-
-
     /**
      * @param id              the if of the object for which the custom fields apply
      * @param customFieldList a comma separated list of custom field ids or null if they should all be removed
@@ -295,23 +292,20 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
      * @throws CustomFieldApiException
      */
     protected Response deleteCustomFields(final UUID id,
-                                          @Nullable final String customFieldList,
+                                          final List<UUID> customFieldList,
                                           final CallContext context) throws CustomFieldApiException {
 
         // Retrieve all the custom fields for the object
         final List<CustomField> fields = customFieldUserApi.getCustomFieldsForObject(id, getObjectType(), context);
 
-        final String[] requestedIds = customFieldList != null ? customFieldList.split("\\s*,\\s*") : null;
-
         // Filter the proposed list to only keep the one that exist and indeed match our object
         final Iterable inputIterable = Iterables.filter(fields, new Predicate<CustomField>() {
             @Override
             public boolean apply(final CustomField input) {
-                if (customFieldList == null) {
+                if (customFieldList.isEmpty()) {
                     return true;
                 }
-                for (final String cur : requestedIds) {
-                    final UUID curId = UUID.fromString(cur);
+                for (final UUID curId : customFieldList) {
                     if (input.getId().equals(curId)) {
                         return true;
                     }
@@ -324,7 +318,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
             final List<CustomField> input = ImmutableList.<CustomField>copyOf(inputIterable);
             customFieldUserApi.removeCustomFields(input, context);
         }
-        return Response.status(Response.Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     protected <E extends Entity, J extends JsonBase> Response buildStreamingPaginationResponse(final Pagination<E> entities,
@@ -384,8 +378,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
     }
 
-
-    protected Response completeTransactionInternal(final PaymentTransactionJson json,
+    protected void completeTransactionInternal(final PaymentTransactionJson json,
                                                    final Payment initialPayment,
                                                    final List<String> paymentControlPluginNames,
                                                    final Iterable<PluginProperty> pluginProperties,
@@ -398,7 +391,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), contextNoAccountId);
         final BigDecimal amount = json == null ? null : json.getAmount();
-        final Currency currency = json == null || json.getCurrency() == null ? null : Currency.valueOf(json.getCurrency());
+        final Currency currency = json == null ? null: json.getCurrency();
 
         final CallContext callContext = context.createCallContextWithAccountId(account.getId(), createdBy, reason, comment, request);
 
@@ -408,45 +401,41 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
                                                                                                  json != null ? json.getTransactionType() : null);
         // If transaction was already completed, return early (See #626)
         if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
-            return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
+            return;
         }
 
         final PaymentTransaction pendingTransaction = pendingOrSuccessTransaction;
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
-        final Payment result;
         switch (pendingTransaction.getTransactionType()) {
             case AUTHORIZE:
-                result = paymentApi.createAuthorizationWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
-                                                                          initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
-                                                                          pluginProperties, paymentOptions, callContext);
+                paymentApi.createAuthorizationWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
+                                                                 initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+                                                                 pluginProperties, paymentOptions, callContext);
                 break;
             case CAPTURE:
-                result = paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), amount, currency, null, pendingTransaction.getExternalKey(),
-                                                                    pluginProperties, paymentOptions, callContext);
+                paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), amount, currency, null, pendingTransaction.getExternalKey(),
+                                                           pluginProperties, paymentOptions, callContext);
                 break;
             case PURCHASE:
-                result = paymentApi.createPurchaseWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
-                                                                     initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
-                                                                     pluginProperties, paymentOptions, callContext);
+                paymentApi.createPurchaseWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
+                                                            initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+                                                            pluginProperties, paymentOptions, callContext);
                 break;
             case CREDIT:
-                result = paymentApi.createCreditWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
-                                                                   initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
-                                                                   pluginProperties, paymentOptions, callContext);
+                paymentApi.createCreditWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, null,
+                                                          initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+                                                          pluginProperties, paymentOptions, callContext);
                 break;
             case REFUND:
-                result = paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), amount, currency, null,
-                                                                   pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
+                paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), amount, currency, null,
+                                                          pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
                 break;
             default:
-                return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed").build();
+                throw new IllegalStateException("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed");
         }
-        return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey(), request);
-
     }
 
-
-    protected PaymentTransaction lookupPendingOrSuccessTransaction(final Payment initialPayment, @Nullable final UUID transactionId, @Nullable final String transactionExternalKey, @Nullable final String transactionType) throws PaymentApiException {
+    protected PaymentTransaction lookupPendingOrSuccessTransaction(final Payment initialPayment, @Nullable final UUID transactionId, @Nullable final String transactionExternalKey, @Nullable final TransactionType transactionType) throws PaymentApiException {
         final Collection<PaymentTransaction> pendingTransaction = Collections2.filter(initialPayment.getTransactions(), new Predicate<PaymentTransaction>() {
             @Override
             public boolean apply(final PaymentTransaction input) {
@@ -459,7 +448,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
                 if (transactionExternalKey != null && !transactionExternalKey.equals(input.getExternalKey())) {
                     return false;
                 }
-                if (transactionType != null && !transactionType.equals(input.getTransactionType().name())) {
+                if (transactionType != null && !transactionType.equals(input.getTransactionType())) {
                     return false;
                 }
                 //
@@ -482,7 +471,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
                     parameterValue = transactionExternalKey;
                 } else if (transactionType != null) {
                     parameterType = "transactionType";
-                    parameterValue = transactionType;
+                    parameterValue = transactionType.name();
                 } else {
                     parameterType = "paymentId";
                     parameterValue = initialPayment.getId().toString();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
index c845a5f..079115b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
@@ -19,13 +19,9 @@ package org.killbill.billing.jaxrs.resources;
 
 import java.util.List;
 
-import javax.annotation.Nullable;
-
 import org.killbill.billing.util.api.AuditLevel;
-import org.killbill.billing.util.audit.AuditLog;
 
 import com.google.common.base.Function;
-import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import io.swagger.annotations.SwaggerDefinition;
@@ -33,6 +29,7 @@ import io.swagger.jaxrs.config.ReaderListener;
 import io.swagger.models.Model;
 import io.swagger.models.Operation;
 import io.swagger.models.Path;
+import io.swagger.models.Response;
 import io.swagger.models.Swagger;
 import io.swagger.models.auth.BasicAuthDefinition;
 import io.swagger.models.parameters.BodyParameter;
@@ -90,6 +87,18 @@ public class KillBillApiDefinition implements ReaderListener {
 
     private void decorateOperation(final Operation op, final String pathName, final String httpMethod, final HeaderParameter apiKeyParam, final HeaderParameter apiSecretParam) {
         if (op != null) {
+
+            // Bug in swagger ? somehow when we only specify a 201, swagger adds a 200 response with the schema response
+            if (httpMethod.equals("POST")) {
+                if (op.getResponses().containsKey("201") && op.getResponses().containsKey("200")) {
+                    final Response resp200 =op.getResponses().remove("200");
+                    final Response resp201 = op.getResponses().get("201");
+                    if (resp201.getSchema() == null) {
+                        resp201.setSchema(resp200.getSchema());
+                    }
+                }
+            }
+
             op.addSecurity(BASIC_AUTH_SCHEME, null);
             if (requiresTenantInformation(pathName, httpMethod)) {
                 op.addParameter(apiKeyParam);
@@ -108,7 +117,6 @@ public class KillBillApiDefinition implements ReaderListener {
                 } else if (p instanceof QueryParameter) {
                     QueryParameter qp = (QueryParameter) p;
                     if (qp.getName().equals(QUERY_AUDIT)) {
-                        qp.setName("auditLevel");
                         qp.setRequired(false);
                         qp.setType("string");
                         final List<String> values = ImmutableList.copyOf(Iterables.transform(ImmutableList.<AuditLevel>copyOf(AuditLevel.values()), new Function<AuditLevel, String>() {
@@ -118,6 +126,20 @@ public class KillBillApiDefinition implements ReaderListener {
                             }
                         }));
                         qp.setEnum(values);
+                    } else if (qp.getName().equals(JaxrsResource.QUERY_REQUESTED_DT) ||
+                               qp.getName().equals(JaxrsResource.QUERY_ENTITLEMENT_REQUESTED_DT) ||
+                               qp.getName().equals(JaxrsResource.QUERY_BILLING_REQUESTED_DT) ||
+                               qp.getName().equals(JaxrsResource.QUERY_ENTITLEMENT_EFFECTIVE_FROM_DT) ||
+                               qp.getName().equals(JaxrsResource.QUERY_START_DATE) ||
+                               qp.getName().equals(JaxrsResource.QUERY_END_DATE) ||
+                               qp.getName().equals(JaxrsResource.QUERY_TARGET_DATE)) {
+                        qp.setType("string");
+                        // Yack... See #922
+                        if (op.getOperationId().equals("getCatalogJson") || op.getOperationId().equals("setTestClockTime")) {
+                            qp.setFormat("date-time");
+                        } else {
+                            qp.setFormat("date");
+                        }
                     }
                 }
             }
@@ -146,7 +168,7 @@ public class KillBillApiDefinition implements ReaderListener {
     }
 
     private static boolean isTenantCreationRequest(final String path, final String httpMethod) {
-        return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equalsIgnoreCase(httpMethod);
+        return JaxrsResource.TENANTS_PATH.equals(path);
     }
 
     private static boolean isNodeInfoRequest(final String path) {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/NodesInfoResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/NodesInfoResource.java
index 69e0d40..c16907c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/NodesInfoResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/NodesInfoResource.java
@@ -146,7 +146,8 @@ public class NodesInfoResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Trigger a node command")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid node command supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 202, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid node command supplied")})
     public Response triggerNodeCommand(final NodeCommandJson json,
                                        @QueryParam(QUERY_LOCAL_NODE_ONLY) @DefaultValue("false") final Boolean localNodeOnly,
                                        @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -173,7 +174,7 @@ public class NodesInfoResource extends JaxRsResourceBase {
         };
 
         killbillInfoApi.triggerNodeCommand(nodeCommand, localNodeOnly);
-        return Response.status(Status.CREATED).build();
+        return Response.status(Status.ACCEPTED).build();
     }
 
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
index 6281a83..782c07a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
@@ -54,14 +54,15 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_XML;
 
 @Singleton
 @Path(JaxrsResource.OVERDUE_PATH)
-@Api(value = JaxrsResource.OVERDUE_PATH, description = "Overdue information", tags="Overdue")
+@Api(value = JaxrsResource.OVERDUE_PATH, description = "Overdue information", tags = "Overdue")
 public class OverdueResource extends JaxRsResourceBase {
 
     private final OverdueApi overdueApi;
@@ -80,40 +81,37 @@ public class OverdueResource extends JaxRsResourceBase {
         this.overdueApi = overdueApi;
     }
 
+    //
+    // We mark this resource as hidden from a swagger point of view and create another one with a different Path below
+    // to hack around the restrictions of having only one type of HTTP verb per Path
+    // see https://github.com/killbill/killbill/issues/913
+    //
     @TimedResource
     @GET
-    @Produces(APPLICATION_XML)
-    @ApiOperation(value = "Retrieve the overdue config as XML", response = String.class, hidden = true)
+    @Produces(TEXT_XML)
+    @ApiOperation(value = "Retrieve the overdue config as XML", response = String.class, hidden=true)
     @ApiResponses(value = {})
-    public Response getOverdueConfigXml(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+    public Response getOverdueConfigXmlOriginal(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        return Response.status(Status.OK).entity(XMLWriter.writeXML((DefaultOverdueConfig )overdueApi.getOverdueConfig(tenantContext), DefaultOverdueConfig.class)).build();
+        return Response.status(Status.OK).entity(XMLWriter.writeXML((DefaultOverdueConfig) overdueApi.getOverdueConfig(tenantContext), DefaultOverdueConfig.class)).build();
     }
 
     @TimedResource
-    @POST
-    @Consumes(APPLICATION_XML)
-    @ApiOperation(value = "Upload the full overdue config as XML")
+    @GET
+    @Path("/xml")
+    @Produces(TEXT_XML)
+    @ApiOperation(value = "Retrieve the overdue config as XML", response = String.class)
     @ApiResponses(value = {})
-    public Response uploadOverdueConfigXml(final String overdueXML,
-                                           @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 HttpServletRequest request,
-                                           @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
-        // Validation purpose:  Will throw if bad XML or catalog validation fails
-        final InputStream stream = new ByteArrayInputStream(overdueXML.getBytes());
-        XMLLoader.getObjectFromStream(new URI(JaxrsResource.OVERDUE_PATH), stream, DefaultOverdueConfig.class);
-
-        final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        overdueApi.uploadOverdueConfig(overdueXML, callContext);
-        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null, request);
+    public Response getOverdueConfigXml(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+        return getOverdueConfigXmlOriginal(request);
     }
 
+
+
     @TimedResource
     @GET
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve the overdue config as JSON" , response = OverdueJson.class)
+    @ApiOperation(value = "Retrieve the overdue config as JSON", response = OverdueJson.class)
     @ApiResponses(value = {})
     public Response getOverdueConfigJson(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -124,18 +122,61 @@ public class OverdueResource extends JaxRsResourceBase {
 
 
 
+    //
+    // We mark this resource as hidden from a swagger point of view and create another one with a different Path below
+    // to hack around the restrictions of having only one type of HTTP verb per Path
+    // see https://github.com/killbill/killbill/issues/913
+    //
+    @TimedResource
+    @POST
+    @Consumes(TEXT_XML)
+    @ApiOperation(value = "Upload the full overdue config as XML", hidden=true)
+    @ApiResponses(value = {})
+    public Response uploadOverdueConfigXmlOriginal(final String overdueXML,
+                                                   @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 HttpServletRequest request,
+                                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        // Validation purpose:  Will throw if bad XML or catalog validation fails
+        final InputStream stream = new ByteArrayInputStream(overdueXML.getBytes());
+        XMLLoader.getObjectFromStream(new URI(JaxrsResource.OVERDUE_PATH), stream, DefaultOverdueConfig.class);
+
+        final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+        overdueApi.uploadOverdueConfig(overdueXML, callContext);
+        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null, request);
+    }
+
+    @TimedResource
+    @POST
+    @Path("/xml")
+    @Consumes(TEXT_XML)
+    @ApiOperation(value = "Upload the full overdue config as XML", response = String.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Successfully uploaded overdue config"),
+                           @ApiResponse(code = 400, message = "Invalid node command supplied")})
+    public Response uploadOverdueConfigXml(final String overdueXML,
+                                                   @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 HttpServletRequest request,
+                                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        return uploadOverdueConfigXmlOriginal(overdueXML, createdBy, reason, comment, request, uriInfo);
+    }
+
+
     @TimedResource
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Upload the full overdue config as JSON")
-    @ApiResponses(value = {})
+    @ApiOperation(value = "Upload the full overdue config as JSON", response = OverdueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Successfully uploaded overdue config"),
+                           @ApiResponse(code = 400, message = "Invalid node command supplied")})
     public Response uploadOverdueConfigJson(final OverdueJson overdueJson,
-                                  @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 HttpServletRequest request,
-                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+                                            @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 HttpServletRequest request,
+                                            @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
         final OverdueConfig overdueConfig = OverdueJson.toOverdueConfigWithValidation(overdueJson);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentGatewayResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentGatewayResource.java
index 818b4ff..93dfef0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentGatewayResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentGatewayResource.java
@@ -92,7 +92,8 @@ public class PaymentGatewayResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Combo API to generate form data to redirect the customer to the gateway", response = HostedPaymentPageFormDescriptorJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid data for Account or PaymentMethod")})
+    @ApiResponses(value = {/*@ApiResponse(code = 200, message = "Successful"),*/
+                           @ApiResponse(code = 400, message = "Invalid data for Account or PaymentMethod")})
     public Response buildComboFormDescriptor(final ComboHostedPaymentPageJson json,
                                              @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                              @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -112,8 +113,8 @@ public class PaymentGatewayResource extends ComboPaymentResource {
         final Iterable<PluginProperty> paymentMethodPluginProperties = extractPluginProperties(json.getPaymentMethodPluginProperties());
         final UUID paymentMethodId = getOrCreatePaymentMethod(account, json.getPaymentMethod(), paymentMethodPluginProperties, callContext);
 
-        final HostedPaymentPageFieldsJson hostedPaymentPageFields = json.getHostedPaymentPageFieldsJson();
-        final Iterable<PluginProperty> customFields = extractPluginProperties(hostedPaymentPageFields != null ? hostedPaymentPageFields.getCustomFields() : null);
+        final HostedPaymentPageFieldsJson hostedPaymentPageFields = json.getHostedPaymentPageFields();
+        final Iterable<PluginProperty> customFields = extractPluginProperties(hostedPaymentPageFields != null ? hostedPaymentPageFields.getFormFields() : null);
 
         final HostedPaymentPageFormDescriptor descriptor = paymentGatewayApi.buildFormDescriptorWithPaymentControl(account, paymentMethodId, customFields, pluginProperties, paymentOptions, callContext);
         final HostedPaymentPageFormDescriptorJson result = new HostedPaymentPageFormDescriptorJson(descriptor);
@@ -127,10 +128,10 @@ public class PaymentGatewayResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Generate form data to redirect the customer to the gateway", response = HostedPaymentPageFormDescriptorJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid accountId supplied"),
+    @ApiResponses(value = {/* @ApiResponse(code = 200, message = "Successful"),*/
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response buildFormDescriptor(final HostedPaymentPageFieldsJson json,
-                                        @PathParam("accountId") final UUID accountId,
+    public Response buildFormDescriptor(@PathParam("accountId") final UUID accountId,
+                                        final HostedPaymentPageFieldsJson json,
                                         @QueryParam(QUERY_PAYMENT_METHOD_ID) final UUID inputPaymentMethodId,
                                         @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                         @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -147,7 +148,7 @@ public class PaymentGatewayResource extends ComboPaymentResource {
 
         validatePaymentMethodForAccount(accountId, paymentMethodId, callContext);
 
-        final Iterable<PluginProperty> customFields = extractPluginProperties(json.getCustomFields());
+        final Iterable<PluginProperty> customFields = extractPluginProperties(json.getFormFields());
 
         final HostedPaymentPageFormDescriptor descriptor = paymentGatewayApi.buildFormDescriptorWithPaymentControl(account, paymentMethodId, customFields, pluginProperties, paymentOptions, callContext);
         final HostedPaymentPageFormDescriptorJson result = new HostedPaymentPageFormDescriptorJson(descriptor);
@@ -161,9 +162,9 @@ public class PaymentGatewayResource extends ComboPaymentResource {
     @Consumes(WILDCARD)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Process a gateway notification", notes = "The response is built by the appropriate plugin")
-    @ApiResponses(value = {})
-    public Response processNotification(final String body,
-                                        @PathParam(QUERY_PAYMENT_PLUGIN_NAME) final String pluginName,
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "Successful")})
+    public Response processNotification(@PathParam(PATH_PAYMENT_PLUGIN_NAME) final String pluginName,
+                                        final String body,
                                         @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                         @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
index 3445337..84e76a5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
@@ -63,6 +63,7 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.audit.AuditLogWithHistory;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
@@ -105,10 +106,10 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentMethodId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment method not found")})
     public Response getPaymentMethod(@PathParam("paymentMethodId") final UUID paymentMethodId,
-                                     @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                      @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
-                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                      @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                     @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -127,10 +128,10 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a payment method by external key", response = PaymentMethodJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Account or payment method not found")})
     public Response getPaymentMethodByKey(@ApiParam(required=true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
-                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                           @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
-                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                           @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -151,9 +152,9 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     public Response getPaymentMethods(@QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                       @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                       @QueryParam(QUERY_PAYMENT_METHOD_PLUGIN_NAME) final String pluginName,
+                                      @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                       @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                      @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -208,9 +209,9 @@ public class PaymentMethodResource extends JaxRsResourceBase {
                                          @QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                          @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                          @QueryParam(QUERY_PAYMENT_METHOD_PLUGIN_NAME) final String pluginName,
+                                         @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                          @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                         @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -262,7 +263,8 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/{paymentMethodId:" + UUID_PATTERN + "}")
     @ApiOperation(value = "Delete a payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentMethodId supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid paymentMethodId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment method not found")})
     public Response deletePaymentMethod(@PathParam("paymentMethodId") final UUID paymentMethodId,
                                         @QueryParam(QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF) @DefaultValue("false") final Boolean deleteDefaultPaymentMethodWithAutoPayOff,
@@ -280,14 +282,14 @@ public class PaymentMethodResource extends JaxRsResourceBase {
 
         paymentApi.deletePaymentMethod(account, paymentMethodId, deleteDefaultPaymentMethodWithAutoPayOff, forceDefaultPaymentMethodDeletion, pluginProperties, callContext);
 
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
     @GET
     @Path("/{paymentMethodId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment method custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment method custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getPaymentMethodCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment method id supplied")})
     public Response getCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -300,15 +302,16 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Path("/{paymentMethodId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment method id supplied")})
-    public Response createCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to payment method", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment method id supplied")})
+    public Response createPaymentMethodCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
+                                                    final List<CustomFieldJson> customFields,
+                                                    @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 HttpServletRequest request,
+                                                    @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(paymentMethodId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -320,13 +323,14 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment method id supplied")})
-    public Response modifyCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment method id supplied")})
+    public Response modifyPaymentMethodCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
+                                                    final List<CustomFieldJson> customFields,
+                                                    @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(paymentMethodId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -338,13 +342,14 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from payment method")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment method id supplied")})
-    public Response deleteCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment method id supplied")})
+    public Response deletePaymentMethodCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
+                                                    @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                                    @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(paymentMethodId, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index 9ceeda6..25d5865 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -72,6 +72,7 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.audit.AuditLogWithHistory;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.MetricTag;
@@ -158,10 +159,10 @@ public class PaymentResource extends ComboPaymentResource {
     public Response getPayments(@QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                 @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                 @QueryParam(QUERY_PAYMENT_PLUGIN_NAME) final String pluginName,
-                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                 @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                 @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
+                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                 @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -202,11 +203,11 @@ public class PaymentResource extends ComboPaymentResource {
     public Response searchPayments(@PathParam("searchKey") final String searchKey,
                                    @QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                    @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
+                                   @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
+                                   @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
                                    @QueryParam(QUERY_PAYMENT_PLUGIN_NAME) final String pluginName,
                                    @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                   @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
-                                   @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
@@ -246,7 +247,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Complete an existing transaction")
-    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -254,8 +255,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response completeTransaction(@MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
-                                        @PathParam("paymentId") final UUID paymentId,
+    public Response completeTransaction(@PathParam("paymentId") final UUID paymentId,
+                                        @MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
                                         @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                         @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -263,7 +264,8 @@ public class PaymentResource extends ComboPaymentResource {
                                         @HeaderParam(HDR_COMMENT) final String comment,
                                         @javax.ws.rs.core.Context final UriInfo uriInfo,
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
-        return completeTransactionInternalWithoutPayment(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        completeTransactionInternalWithoutPayment(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -273,7 +275,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Complete an existing transaction")
-    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
                            @ApiResponse(code = 422, message = "Payment is aborted by a control plugin"),
@@ -288,7 +290,8 @@ public class PaymentResource extends ComboPaymentResource {
                                                      @HeaderParam(HDR_COMMENT) final String comment,
                                                      @javax.ws.rs.core.Context final UriInfo uriInfo,
                                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
-        return completeTransactionInternalWithoutPayment(json, null, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        completeTransactionInternalWithoutPayment(json, null, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -302,7 +305,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Capture an existing authorization")
+    @ApiOperation(value = "Capture an existing authorization", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
@@ -311,8 +314,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response captureAuthorization(final PaymentTransactionJson json,
-                                         @PathParam("paymentId") final UUID paymentId,
+    public Response captureAuthorization(@PathParam("paymentId") final UUID paymentId,
+                                         final PaymentTransactionJson json,
                                          @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -327,7 +330,7 @@ public class PaymentResource extends ComboPaymentResource {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Capture an existing authorization")
+    @ApiOperation(value = "Capture an existing authorization", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -366,7 +369,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Payment initialPayment = getPaymentByIdOrKey(paymentId, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
-        final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
+        final Currency currency = json.getCurrency() == null ? account.getCurrency() : json.getCurrency();
 
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
 
@@ -380,7 +383,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + REFUNDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Refund an existing payment")
+    @ApiOperation(value = "Refund an existing payment", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
@@ -389,8 +392,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response refundPayment(final PaymentTransactionJson json,
-                                  @PathParam("paymentId") final UUID paymentId,
+    public Response refundPayment(@PathParam("paymentId") final UUID paymentId,
+                                  final PaymentTransactionJson json,
                                   @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                   @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -406,7 +409,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/" + REFUNDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Refund an existing payment")
+    @ApiOperation(value = "Refund an existing payment", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -447,7 +450,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Payment initialPayment = getPaymentByIdOrKey(paymentId, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
-        final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
+        final Currency currency = json.getCurrency() == null ? account.getCurrency() : json.getCurrency();
 
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
 
@@ -463,7 +466,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Void an existing payment")
-    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -471,8 +474,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response voidPayment(final PaymentTransactionJson json,
-                                @PathParam("paymentId") final UUID paymentId,
+    public Response voidPayment(@PathParam("paymentId") final UUID paymentId,
+                                final PaymentTransactionJson json,
                                 @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -488,7 +491,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Void an existing payment")
-    @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
                            @ApiResponse(code = 422, message = "Payment is aborted by a control plugin"),
@@ -527,9 +530,10 @@ public class PaymentResource extends ComboPaymentResource {
         final String transactionExternalKey = json != null ? json.getTransactionExternalKey() : null;
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
 
-        final Payment payment = paymentApi.createVoidWithPaymentControl(account, initialPayment.getId(), json.getEffectiveDate(), transactionExternalKey,
-                                                                        pluginProperties, paymentOptions, callContext);
-        return createPaymentResponse(uriInfo, payment, TransactionType.VOID, json.getTransactionExternalKey(), request);
+        paymentApi.createVoidWithPaymentControl(account, initialPayment.getId(), json.getEffectiveDate(), transactionExternalKey,
+                                                pluginProperties, paymentOptions, callContext);
+
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource(name = "chargebackPayment")
@@ -537,7 +541,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACKS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargeback")
+    @ApiOperation(value = "Record a chargeback", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
@@ -546,8 +550,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response chargebackPayment(final PaymentTransactionJson json,
-                                      @PathParam("paymentId") final UUID paymentId,
+    public Response chargebackPayment(@PathParam("paymentId") final UUID paymentId,
+                                      final PaymentTransactionJson json,
                                       @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                       @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -563,7 +567,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/" + CHARGEBACKS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargeback")
+    @ApiOperation(value = "Record a chargeback", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -602,7 +606,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Payment initialPayment = getPaymentByIdOrKey(paymentId, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
-        final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
+        final Currency currency = json.getCurrency() == null ? account.getCurrency() : json.getCurrency();
 
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
 
@@ -616,7 +620,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACK_REVERSALS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargeback reversal")
+    @ApiOperation(value = "Record a chargeback reversal", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
@@ -625,8 +629,8 @@ public class PaymentResource extends ComboPaymentResource {
                            @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
                            @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
                            @ApiResponse(code = 504, message = "Payment operation timeout")})
-    public Response chargebackReversalPayment(final PaymentTransactionJson json,
-                                              @PathParam("paymentId") final UUID paymentId,
+    public Response chargebackReversalPayment(@PathParam("paymentId") final UUID paymentId,
+                                              final PaymentTransactionJson json,
                                               @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                               @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -642,7 +646,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/" + CHARGEBACK_REVERSALS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Record a chargeback reversal")
+    @ApiOperation(value = "Record a chargeback reversal", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 404, message = "Account or payment not found"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -690,7 +694,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @Path("/" + COMBO)
-    @ApiOperation(value = "Combo api to create a new payment transaction on a existing (or not) account ")
+    @ApiOperation(value = "Combo api to create a new payment transaction on a existing (or not) account ", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
                            @ApiResponse(code = 400, message = "Invalid data for Account or PaymentMethod"),
                            @ApiResponse(code = 402, message = "Transaction declined by gateway"),
@@ -715,13 +719,13 @@ public class PaymentResource extends ComboPaymentResource {
         final UUID paymentMethodId = getOrCreatePaymentMethod(account, json.getPaymentMethod(), paymentMethodPluginProperties, callContext);
 
         final PaymentTransactionJson paymentTransactionJson = json.getTransaction();
-        final TransactionType transactionType = TransactionType.valueOf(paymentTransactionJson.getTransactionType());
+        final TransactionType transactionType = paymentTransactionJson.getTransactionType();
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
         final Payment result;
 
         final Iterable<PluginProperty> transactionPluginProperties = extractPluginProperties(json.getTransactionPluginProperties());
 
-        final Currency currency = paymentTransactionJson.getCurrency() == null ? account.getCurrency() : Currency.valueOf(paymentTransactionJson.getCurrency());
+        final Currency currency = paymentTransactionJson.getCurrency() == null ? account.getCurrency() : paymentTransactionJson.getCurrency();
         final UUID paymentId = null; // If we need to specify a paymentId (e.g 3DS authorization, we can use regular API, no need for combo call)
         switch (transactionType) {
             case AUTHORIZE:
@@ -751,7 +755,8 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Cancels a scheduled payment attempt retry")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid paymentTransactionId supplied")})
     public Response cancelScheduledPaymentTransactionById(@PathParam("paymentTransactionId") final UUID paymentTransactionId,
                                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                           @HeaderParam(HDR_REASON) final String reason,
@@ -760,7 +765,7 @@ public class PaymentResource extends ComboPaymentResource {
                                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         paymentApi.cancelScheduledPaymentTransaction(paymentTransactionId, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource(name = "cancelScheduledPaymentTransaction")
@@ -769,7 +774,8 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Cancels a scheduled payment attempt retry")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionExternalKey supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid paymentTransactionExternalKey supplied")})
     public Response cancelScheduledPaymentTransactionByExternalKey(@ApiParam(required=true) @QueryParam(QUERY_TRANSACTION_EXTERNAL_KEY) final String paymentTransactionExternalKey,
                                                                    @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                                    @HeaderParam(HDR_REASON) final String reason,
@@ -778,17 +784,16 @@ public class PaymentResource extends ComboPaymentResource {
                                                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         paymentApi.cancelScheduledPaymentTransaction(paymentTransactionExternalKey, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
 
-
     @TimedResource
     @GET
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getPaymentCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -801,15 +806,16 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to payment", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response createPaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request,
+                                              @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -820,13 +826,14 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response modifyPaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              final List<CustomFieldJson> customFields,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -837,13 +844,14 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from payment payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response deletePaymentCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                              @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                              @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -852,12 +860,12 @@ public class PaymentResource extends ComboPaymentResource {
     @GET
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment payment tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment payment tags", response = TagJson.class, responseContainer = "List", nickname = "getPaymentTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
@@ -869,15 +877,16 @@ public class PaymentResource extends ComboPaymentResource {
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to payment payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to payment payment", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response createPaymentTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
+                                      final List<UUID> tagList,
+                                      @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,
+                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(paymentId, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -888,13 +897,14 @@ public class PaymentResource extends ComboPaymentResource {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from payment payment")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid payment id supplied")})
+    public Response deletePaymentTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
+                                      @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                      @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(paymentId, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -930,7 +940,7 @@ public class PaymentResource extends ComboPaymentResource {
         return ObjectType.PAYMENT;
     }
 
-    private Response completeTransactionInternalWithoutPayment(final PaymentTransactionJson json,
+    private void completeTransactionInternalWithoutPayment(final PaymentTransactionJson json,
                                                                @Nullable final UUID paymentId,
                                                                final List<String> paymentControlPluginNames,
                                                                final Iterable<String> pluginPropertiesString,
@@ -949,7 +959,7 @@ public class PaymentResource extends ComboPaymentResource {
         final CallContext callContextNoAccountId = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final Payment initialPayment = getPaymentByIdOrKey(paymentId, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContextNoAccountId);
 
-        return completeTransactionInternal(json, initialPayment, paymentControlPluginNames, pluginProperties, callContextNoAccountId, createdBy, reason, comment, uriInfo, request);
+        completeTransactionInternal(json, initialPayment, paymentControlPluginNames, pluginProperties, callContextNoAccountId, createdBy, reason, comment, uriInfo, request);
     }
 
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
index 5b85cf5..f9900a1 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
@@ -59,6 +59,7 @@ import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@@ -115,7 +116,8 @@ public class SecurityResource extends JaxRsResourceBase {
     @Path("/users")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a new user with roles (to make api requests)")
+    @ApiOperation(value = "Add a new user with roles (to make api requests)", response = UserRolesJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "User role created successfully")})
     public Response addUserRoles(final UserRolesJson json,
                                  @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                  @HeaderParam(HDR_REASON) final String reason,
@@ -123,7 +125,7 @@ public class SecurityResource extends JaxRsResourceBase {
                                  @javax.ws.rs.core.Context final HttpServletRequest request,
                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
         securityApi.addUserRoles(json.getUsername(), json.getPassword(), json.getRoles(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.CREATED).build();
+        return uriBuilder.buildResponse(uriInfo, SecurityResource.class, "getUserRoles", json.getUsername(), request);
     }
 
     @TimedResource
@@ -132,15 +134,16 @@ public class SecurityResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/users/{username:" + ANYTHING_PATTERN + "}/password")
     @ApiOperation(value = "Update a user password")
-    public Response updateUserPassword(final UserRolesJson json,
-                                       @PathParam("username") final String username,
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
+    public Response updateUserPassword(@PathParam("username") final String username,
+                                       final UserRolesJson 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 HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
         securityApi.updateUserPassword(username, json.getPassword(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -162,15 +165,16 @@ public class SecurityResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/users/{username:" + ANYTHING_PATTERN + "}/roles")
     @ApiOperation(value = "Update roles associated to a user")
-    public Response updateUserRoles(final UserRolesJson json,
-                                    @PathParam("username") final String username,
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
+     public Response updateUserRoles(@PathParam("username") final String username,
+                                    final UserRolesJson 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 HttpServletRequest request,
                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
         securityApi.updateUserRoles(username, json.getRoles(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -179,6 +183,7 @@ public class SecurityResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/users/{username:" + ANYTHING_PATTERN + "}")
     @ApiOperation(value = "Invalidate an existing user")
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
     public Response invalidateUser(@PathParam("username") final String username,
                                    @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                    @HeaderParam(HDR_REASON) final String reason,
@@ -189,12 +194,28 @@ public class SecurityResource extends JaxRsResourceBase {
         return Response.status(Status.NO_CONTENT).build();
     }
 
+
+    @TimedResource
+    @GET
+    @Produces(APPLICATION_JSON)
+    @Path("/roles/{role:" + ANYTHING_PATTERN + "}")
+    @ApiOperation(value = "Get role definition", response = RoleDefinitionJson.class)
+    public Response getRoleDefinition(@PathParam("role") final String role,
+                                 @javax.ws.rs.core.Context final HttpServletRequest request,
+                                 @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
+        final List<String> roleDefinitions =  securityApi.getRoleDefinition(role, context.createTenantContextNoAccountId(request));
+        final RoleDefinitionJson result =  new RoleDefinitionJson(role, roleDefinitions);
+        return Response.status(Status.OK).entity(result).build();
+    }
+
+
     @TimedResource
     @POST
     @Path("/roles")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a new role definition)")
+    @ApiOperation(value = "Add a new role definition)", response = RoleDefinitionJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Role definition created successfully")})
     public Response addRoleDefinition(final RoleDefinitionJson json,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
@@ -202,7 +223,7 @@ public class SecurityResource extends JaxRsResourceBase {
                                       @javax.ws.rs.core.Context final HttpServletRequest request,
                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
         securityApi.addRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.CREATED).build();
+        return uriBuilder.buildResponse(uriInfo, SecurityResource.class, "getRoleDefinition", json.getRole(), request);
     }
 
 
@@ -212,6 +233,7 @@ public class SecurityResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @Path("/roles")
     @ApiOperation(value = "Update a new role definition)")
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation")})
     public Response updateRoleDefinition(final RoleDefinitionJson json,
                                     @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                     @HeaderParam(HDR_REASON) final String reason,
@@ -219,7 +241,7 @@ public class SecurityResource extends JaxRsResourceBase {
                                     @javax.ws.rs.core.Context final HttpServletRequest request,
                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
         securityApi.updateRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index 35f7c60..1d50fdb 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -51,7 +51,6 @@ import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PhaseType;
@@ -89,7 +88,6 @@ import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.jaxrs.util.KillbillEventHandler;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldApiException;
 import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -111,13 +109,14 @@ import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Path(JaxrsResource.SUBSCRIPTIONS_PATH)
-@Api(value = JaxrsResource.SUBSCRIPTIONS_PATH, description = "Operations on subscriptions", tags="Subscription")
+@Api(value = JaxrsResource.SUBSCRIPTIONS_PATH, description = "Operations on subscriptions", tags = "Subscription")
 public class SubscriptionResource extends JaxRsResourceBase {
 
     private static final Logger log = LoggerFactory.getLogger(SubscriptionResource.class);
@@ -152,9 +151,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a subscription by id", response = SubscriptionJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Subscription not found")})
-    public Response getEntitlement(@PathParam("subscriptionId") final UUID subscriptionId,
-                                   @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, CatalogApiException {
+    public Response getSubscription(@PathParam("subscriptionId") final UUID subscriptionId,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, CatalogApiException {
         final TenantContext context = this.context.createTenantContextNoAccountId(request);
         final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(subscriptionId, context);
         final Account account = accountUserApi.getAccountById(subscription.getAccountId(), context);
@@ -167,77 +166,78 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create an entitlement")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid entitlement supplied")})
-    public Response createEntitlement(final SubscriptionJson entitlement,
-                                      @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
-                                      @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
-                                      @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
-                                      @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
-                                      @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
-                                      @QueryParam(QUERY_BCD) final Integer newBCD,
-                                      @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-                                      @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
-                                      @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                      @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 HttpServletRequest request,
-                                      @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
-        final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns = ImmutableList.of(new BulkSubscriptionsBundleJson(ImmutableList.<SubscriptionJson>of(entitlement)));
-        return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.SUBSCRIPTION);
+
+    @ApiOperation(value = "Create an subscription", response = SubscriptionJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Subscription created successfully")})
+    public Response createSubscription(final SubscriptionJson subscription,
+                                       @ApiParam(hidden = true) @Deprecated @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
+                                       @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
+                                       @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
+                                       @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
+                                       @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+                                       @QueryParam(QUERY_BCD) final Integer newBCD,
+                                       @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+                                       @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+                                       @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                       @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 HttpServletRequest request,
+                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+        final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns = ImmutableList.of(new BulkSubscriptionsBundleJson(ImmutableList.<SubscriptionJson>of(subscription)));
+        return createSubscriptionsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.SUBSCRIPTION);
     }
 
     @TimedResource
     @POST
-    @Path("/createEntitlementWithAddOns")
+    @Path("/createSubscriptionWithAddOns")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Create an entitlement with addOn products", response = BundleJson.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid entitlement supplied")})
-    public Response createEntitlementWithAddOns(final List<SubscriptionJson> entitlements,
-                                                @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
-                                                @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
-                                                @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
-                                                @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
-                                                @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
-                                                @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-                                                @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
-                                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                                @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 HttpServletRequest request,
-                                                @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Subscriptions created successfully")})
+    public Response createSubscriptionWithAddOns(final List<SubscriptionJson> entitlements,
+                                                 @ApiParam(hidden = true) @Deprecated  @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
+                                                 @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
+                                                 @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
+                                                 @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+                                                 @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
+                                                 @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+                                                 @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+                                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                                 @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 HttpServletRequest request,
+                                                 @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
         final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns = ImmutableList.of(new BulkSubscriptionsBundleJson(entitlements));
-        return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.BUNDLE);
+        return createSubscriptionsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.BUNDLE);
     }
 
     @TimedResource
     @POST
-    @Path("/createEntitlementsWithAddOns")
+    @Path("/createSubscriptionsWithAddOns")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Create multiple entitlements with addOn products", response = BundleJson.class, responseContainer = "List")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid entitlements supplied")})
-    public Response createEntitlementsWithAddOns(final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns,
-                                                @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
-                                                @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
-                                                @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
-                                                 @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
-                                                 @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
-                                                @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-                                                @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
-                                                @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                                @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 HttpServletRequest request,
-                                                @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
-        return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.ACCOUNT);
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Subscriptions created successfully")})
+    public Response createSubscriptionsWithAddOns(final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns,
+                                                  @ApiParam(hidden = true) @Deprecated  @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
+                                                  @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
+                                                  @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
+                                                  @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
+                                                  @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+                                                  @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+                                                  @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+                                                  @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                                  @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 HttpServletRequest request,
+                                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+        return createSubscriptionsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.ACCOUNT);
     }
 
-    private Response createEntitlementsWithAddOnsInternal(final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns,
+    public Response createSubscriptionsWithAddOnsInternal(final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns,
                                                           final String requestedDate,
                                                           final String entitlementDate,
                                                           final String billingDate,
@@ -263,6 +263,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
         final Account account = accountUserApi.getAccountById(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns().get(0).getAccountId(), callContext);
 
         final Collection<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+
         for (final BulkSubscriptionsBundleJson subscriptionsBundleJson : entitlementsWithAddOns) {
             UUID bundleId = null;
             String bundleExternalKey = null;
@@ -322,7 +323,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
             @Override
             public Response doResponseOk(final List<UUID> entitlementIds) {
                 if (responseObject == ObjectType.SUBSCRIPTION) {
-                    return uriBuilder.buildResponse(uriInfo, SubscriptionResource.class, "getEntitlement", Iterables.getFirst(entitlementIds, null), request);
+                    return uriBuilder.buildResponse(uriInfo, SubscriptionResource.class, "getSubscription", Iterables.getFirst(entitlementIds, null), request);
                 }
 
                 final Collection<String> bundleIds = new LinkedHashSet<String>();
@@ -363,9 +364,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
         final PlanPhaseSpecifier planPhaseSpecifier = subscriptionJson.getPlanName() != null ?
                                                       new PlanPhaseSpecifier(subscriptionJson.getPlanName(), null) :
                                                       new PlanPhaseSpecifier(subscriptionJson.getProductName(),
-                                                                             BillingPeriod.valueOf(subscriptionJson.getBillingPeriod()),
+                                                                             subscriptionJson.getBillingPeriod(),
                                                                              subscriptionJson.getPriceList(),
-                                                                             subscriptionJson.getPhaseType() == null ? null : PhaseType.valueOf(subscriptionJson.getPhaseType()));
+                                                                             subscriptionJson.getPhaseType());
         final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(subscriptionJson.getPriceOverrides(),
                                                                                                         planPhaseSpecifier,
                                                                                                         currency);
@@ -429,7 +430,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
         for (String bundleId : bundleIdList) {
             if (value.equals("")) {
                 value += bundleId;
-            } else value+="," + bundleId;
+            } else {
+                value += "," + bundleId;
+            }
         }
         queryParams.put(QUERY_BUNDLES_FILTER, value);
         return queryParams;
@@ -440,18 +443,19 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + UNDO_CANCEL)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Un-cancel an entitlement")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response uncancelEntitlementPlan(@PathParam("subscriptionId") final UUID subscriptionId,
-                                            @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                            @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 HttpServletRequest request) throws EntitlementApiException {
+    public Response uncancelSubscriptionPlan(@PathParam("subscriptionId") final UUID subscriptionId,
+                                             @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                             @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 HttpServletRequest request) throws EntitlementApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final Entitlement current = entitlementApi.getEntitlementForId(subscriptionId, context.createCallContextNoAccountId(createdBy, reason, comment, request));
         current.uncancelEntitlement(pluginProperties, context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -459,18 +463,19 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + UNDO_CHANGE_PLAN)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Undo a pending change plan on an entitlement")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response undoChangeEntitlementPlan(@PathParam("subscriptionId") final UUID subscriptionId,
-                                            @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                            @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 HttpServletRequest request) throws EntitlementApiException {
+    public Response undoChangeSubscriptionPlan(@PathParam("subscriptionId") final UUID subscriptionId,
+                                               @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                               @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 HttpServletRequest request) throws EntitlementApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final Entitlement current = entitlementApi.getEntitlementForId(subscriptionId, context.createCallContextNoAccountId(createdBy, reason, comment, request));
         current.undoChangePlan(pluginProperties, context.createCallContextNoAccountId(createdBy, reason, comment, request));
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @TimedResource
@@ -479,19 +484,20 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Path("/{subscriptionId:" + UUID_PATTERN + "}")
     @ApiOperation(value = "Change entitlement plan")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response changeEntitlementPlan(final SubscriptionJson entitlement,
-                                          @PathParam("subscriptionId") final UUID subscriptionId,
-                                          @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-                                          @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-                                          @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
-                                          @QueryParam(QUERY_BILLING_POLICY) final String policyString,
-                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                          @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 HttpServletRequest request) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+    public Response changeSubscriptionPlan(@PathParam("subscriptionId") final UUID subscriptionId,
+                                           final SubscriptionJson entitlement,
+                                           @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                           @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+                                           @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+                                           @QueryParam(QUERY_BILLING_POLICY) final BillingActionPolicy billingPolicy,
+                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                           @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 HttpServletRequest request) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
         verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified");
         if (entitlement.getPlanName() == null) {
             verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set",
@@ -515,25 +521,24 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 final Entitlement newEntitlement;
 
                 final Account account = accountUserApi.getAccountById(current.getAccountId(), callContext);
-                final PhaseType phaseType = entitlement.getPhaseType() != null ? PhaseType.valueOf(entitlement.getPhaseType()) : null;
+                final PhaseType phaseType = entitlement.getPhaseType();
                 final PlanPhaseSpecifier planSpec = entitlement.getPlanName() != null ?
-                                               new PlanPhaseSpecifier(entitlement.getPlanName(), phaseType) :
-                                               new PlanPhaseSpecifier(entitlement.getProductName(),
-                                                                 BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), phaseType);
+                                                    new PlanPhaseSpecifier(entitlement.getPlanName(), phaseType) :
+                                                    new PlanPhaseSpecifier(entitlement.getProductName(),
+                                                                           entitlement.getBillingPeriod(), entitlement.getPriceList(), phaseType);
                 final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
 
-                if (requestedDate == null && policyString == null) {
+                if (requestedDate == null && billingPolicy == null) {
                     newEntitlement = current.changePlan(planSpec, overrides, pluginProperties, ctx);
-                } else if (policyString == null) {
+                } else if (billingPolicy == null) {
                     newEntitlement = current.changePlanWithDate(planSpec, overrides, inputLocalDate, pluginProperties, ctx);
                 } else {
-                    final BillingActionPolicy policy = BillingActionPolicy.valueOf(policyString.toUpperCase());
-                    newEntitlement = current.changePlanOverrideBillingPolicy(planSpec, overrides, null, policy, pluginProperties, ctx);
+                    newEntitlement = current.changePlanOverrideBillingPolicy(planSpec, overrides, null, billingPolicy, pluginProperties, ctx);
                 }
                 isImmediateOp = newEntitlement.getLastActiveProduct().getName().equals(entitlement.getProductName()) &&
-                                newEntitlement.getLastActivePlan().getRecurringBillingPeriod() == BillingPeriod.valueOf(entitlement.getBillingPeriod()) &&
+                                newEntitlement.getLastActivePlan().getRecurringBillingPeriod() == entitlement.getBillingPeriod() &&
                                 newEntitlement.getLastActivePriceList().getName().equals(entitlement.getPriceList());
-                return Response.status(Status.OK).build();
+                return Response.status(Status.NO_CONTENT).build();
             }
 
             @Override
@@ -546,7 +551,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 if (operationResponse.getStatus() != Status.OK.getStatusCode()) {
                     return operationResponse;
                 }
-                return getEntitlement(subscriptionId, new AuditMode(AuditLevel.NONE.toString()), request);
+                return Response.status(Status.NO_CONTENT).build();
             }
         };
 
@@ -555,22 +560,25 @@ public class SubscriptionResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @PUT
+    @POST
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + BLOCK)
     @Consumes(APPLICATION_JSON)
-    @ApiOperation(value = "Block a subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+    @ApiOperation(value = "Block a subscription", response = BlockingStateJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Blocking state created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Subscription not found")})
-    public Response addSubscriptionBlockingState(final BlockingStateJson json,
-                                                 @PathParam(ID_PARAM_NAME) final UUID id,
+    public Response addSubscriptionBlockingState(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                 final BlockingStateJson json,
                                                  @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                                  @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                                  @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 HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
-
-        return addBlockingState(json, id, BlockingStateType.SUBSCRIPTION, requestedDate, pluginPropertiesString, createdBy, reason, comment, request);
+                                                 @javax.ws.rs.core.Context final HttpServletRequest request,
+                                                 @javax.ws.rs.core.Context final UriInfo uriInfo) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
+        final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
+        final Entitlement entitlement = entitlementApi.getEntitlementForId(id, tenantContext);
+        return addBlockingState(json, entitlement.getAccountId(), id, BlockingStateType.SUBSCRIPTION, requestedDate, pluginPropertiesString, createdBy, reason, comment, request, uriInfo);
     }
 
     @TimedResource
@@ -578,21 +586,22 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/{subscriptionId:" + UUID_PATTERN + "}")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Cancel an entitlement plan")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response cancelEntitlementPlan(@PathParam("subscriptionId") final UUID subscriptionId,
-                                          @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-                                          @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-                                          @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("5") final long timeoutSec,
-                                          @QueryParam(QUERY_ENTITLEMENT_POLICY) final String entitlementPolicyString,
-                                          @QueryParam(QUERY_BILLING_POLICY) final String billingPolicyString,
-                                          @QueryParam(QUERY_USE_REQUESTED_DATE_FOR_BILLING) @DefaultValue("false") final Boolean useRequestedDateForBilling,
-                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
-                                          @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,
-                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+    public Response cancelSubscriptionPlan(@PathParam("subscriptionId") final UUID subscriptionId,
+                                           @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                           @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+                                           @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("5") final long timeoutSec,
+                                           @QueryParam(QUERY_ENTITLEMENT_POLICY) final EntitlementActionPolicy entitlementPolicy,
+                                           @QueryParam(QUERY_BILLING_POLICY) final BillingActionPolicy billingPolicy,
+                                           @QueryParam(QUERY_USE_REQUESTED_DATE_FOR_BILLING) @DefaultValue("false") final Boolean useRequestedDateForBilling,
+                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                           @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,
+                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
 
@@ -607,17 +616,13 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 final Entitlement current = entitlementApi.getEntitlementForId(subscriptionId, ctx);
                 final LocalDate inputLocalDate = toLocalDate(requestedDate);
                 final Entitlement newEntitlement;
-                if (billingPolicyString == null && entitlementPolicyString == null) {
+                if (billingPolicy == null && entitlementPolicy == null) {
                     newEntitlement = current.cancelEntitlementWithDate(inputLocalDate, useRequestedDateForBilling, pluginProperties, ctx);
-                } else if (billingPolicyString == null && entitlementPolicyString != null) {
-                    final EntitlementActionPolicy entitlementPolicy = EntitlementActionPolicy.valueOf(entitlementPolicyString);
+                } else if (billingPolicy == null && entitlementPolicy != null) {
                     newEntitlement = current.cancelEntitlementWithPolicy(entitlementPolicy, pluginProperties, ctx);
-                } else if (billingPolicyString != null && entitlementPolicyString == null) {
-                    final BillingActionPolicy billingPolicy = BillingActionPolicy.valueOf(billingPolicyString.toUpperCase());
+                } else if (billingPolicy != null && entitlementPolicy == null) {
                     newEntitlement = current.cancelEntitlementWithDateOverrideBillingPolicy(inputLocalDate, billingPolicy, pluginProperties, ctx);
                 } else {
-                    final EntitlementActionPolicy entitlementPolicy = EntitlementActionPolicy.valueOf(entitlementPolicyString);
-                    final BillingActionPolicy billingPolicy = BillingActionPolicy.valueOf(billingPolicyString.toUpperCase());
                     newEntitlement = current.cancelEntitlementWithPolicyOverrideBillingPolicy(entitlementPolicy, billingPolicy, pluginProperties, ctx);
                 }
 
@@ -626,7 +631,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 final LocalDate nowInAccountTimeZone = new LocalDate(callContext.getCreatedDate(), subscription.getBillingEndDate().getChronology().getZone());
                 isImmediateOp = subscription.getBillingEndDate() != null &&
                                 !subscription.getBillingEndDate().isAfter(nowInAccountTimeZone);
-                return Response.status(Status.OK).build();
+                return Response.status(Status.NO_CONTENT).build();
             }
 
             @Override
@@ -650,9 +655,10 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + BCD)
     @ApiOperation(value = "Update the BCD associated to a subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid entitlement supplied")})
-    public Response updateSubscriptionBCD(final SubscriptionJson json,
-                                          @PathParam(ID_PARAM_NAME) final UUID subscriptionId,
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid entitlement supplied")})
+    public Response updateSubscriptionBCD(@PathParam(ID_PARAM_NAME) final UUID subscriptionId,
+                                          final SubscriptionJson json,
                                           @QueryParam(QUERY_ENTITLEMENT_EFFECTIVE_FROM_DT) final String effectiveFromDateStr,
                                           @QueryParam(QUERY_FORCE_NEW_BCD_WITH_PAST_EFFECTIVE_DATE) @DefaultValue("false") final Boolean forceNewBcdWithPastEffectiveDate,
                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -687,9 +693,8 @@ public class SubscriptionResource extends JaxRsResourceBase {
                     break;
             }
         }
-
         entitlement.updateBCD(json.getBillCycleDayLocal(), effectiveFromDate, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     private static final class CompletionUserRequestEntitlement extends CompletionUserRequestBase {
@@ -797,7 +802,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @GET
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve subscription custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve subscription custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getSubscriptionCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -810,14 +815,15 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Add custom fields to subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied")})
+    public Response createSubscriptionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                   final List<CustomFieldJson> customFields,
+                                                   @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 HttpServletRequest request,
+                                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -827,13 +833,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied")})
+    public Response modifySubscriptionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                   final List<CustomFieldJson> customFields,
+                                                   @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -843,14 +850,15 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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,
-                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied")})
+    public Response deleteSubscriptionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                   @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                                   @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,
+                                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -858,12 +866,12 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @GET
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve subscription tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve subscription tags", response = TagJson.class, responseContainer = "List", nickname = "getSubscriptionTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Subscription not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID subscriptionId,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(subscriptionId, tenantContext);
@@ -874,15 +882,15 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied")})
+    public Response createSubscriptionTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                           final List<UUID> tagList,
+                                           @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,
+                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -892,13 +900,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid subscription id supplied")})
+    public Response deleteSubscriptionTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                           @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                           @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
index cf9c557..d72811b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
@@ -122,8 +122,9 @@ public class TagDefinitionResource extends JaxRsResourceBase {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create a tag definition")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid name or description supplied")})
+    @ApiOperation(value = "Create a tag definition", response = TagDefinitionJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag definition created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid name or description supplied")})
     public Response createTagDefinition(final TagDefinitionJson json,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                         @HeaderParam(HDR_REASON) final String reason,
@@ -138,7 +139,7 @@ public class TagDefinitionResource extends JaxRsResourceBase {
                                     !json.getApplicableObjectTypes().isEmpty(), "Applicable object types must be set");
 
 
-        final TagDefinition createdTagDef = tagUserApi.createTagDefinition(json.getName(), json.getDescription(), TagDefinitionJson.toObjectType(json.getApplicableObjectTypes()), context.createCallContextNoAccountId(createdBy, reason, comment, request));
+        final TagDefinition createdTagDef = tagUserApi.createTagDefinition(json.getName(), json.getDescription(), json.getApplicableObjectTypes(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
         return uriBuilder.buildResponse(uriInfo, TagDefinitionResource.class, "getTagDefinition", createdTagDef.getId(), request);
     }
 
@@ -147,7 +148,8 @@ public class TagDefinitionResource extends JaxRsResourceBase {
     @Path("/{tagDefinitionId:" + UUID_PATTERN + "}")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Delete a tag definition")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tagDefinitionId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tagDefinitionId supplied")})
     public Response deleteTagDefinition(@PathParam("tagDefinitionId") final UUID tagDefId,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                         @HeaderParam(HDR_REASON) final String reason,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
index 8a154eb..dabce06 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
@@ -37,14 +37,13 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
-import org.joda.time.DateTime;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.callcontext.DefaultCallContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogUserApi;
 import org.killbill.billing.jaxrs.json.TenantJson;
-import org.killbill.billing.jaxrs.json.TenantKeyJson;
+import org.killbill.billing.jaxrs.json.TenantKeyValueJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.payment.api.PaymentApi;
@@ -123,8 +122,9 @@ public class TenantResource extends JaxRsResourceBase {
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create a tenant")
-    @ApiResponses(value = {@ApiResponse(code = 409, message = "Tenant already exists")})
+    @ApiOperation(value = "Create a tenant", response = TenantJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tenant created successfully"),
+                           @ApiResponse(code = 409, message = "Tenant already exists")})
     public Response createTenant(final TenantJson json,
                                  @QueryParam(QUERY_TENANT_USE_GLOBAL_DEFAULT) @DefaultValue("false") final Boolean useGlobalDefault,
                                  @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -153,8 +153,9 @@ public class TenantResource extends JaxRsResourceBase {
     @Path("/" + REGISTER_NOTIFICATION_CALLBACK)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create a push notification")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiOperation(value = "Create a push notification", response = TenantKeyValueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Push notification registered successfully"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response registerPushNotificationCallback(@QueryParam(QUERY_NOTIFICATION_CALLBACK) final String notificationCallback,
                                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                      @HeaderParam(HDR_REASON) final String reason,
@@ -168,7 +169,7 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + REGISTER_NOTIFICATION_CALLBACK)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a push notification", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a push notification", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getPushNotificationCallbacks(@javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
         return getTenantKey(TenantKey.PUSH_NOTIFICATION_CB, null, request);
@@ -178,7 +179,8 @@ public class TenantResource extends JaxRsResourceBase {
     @DELETE
     @Path("/" + REGISTER_NOTIFICATION_CALLBACK)
     @ApiOperation(value = "Delete a push notification")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response deletePushNotificationCallbacks(@HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                     @HeaderParam(HDR_REASON) final String reason,
                                                     @HeaderParam(HDR_COMMENT) final String comment,
@@ -191,10 +193,11 @@ public class TenantResource extends JaxRsResourceBase {
     @Path("/" + UPLOAD_PLUGIN_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @Consumes(TEXT_PLAIN)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a per tenant configuration for a plugin")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
-    public Response uploadPluginConfiguration(final String pluginConfig,
-                                              @PathParam("pluginName") final String pluginName,
+    @ApiOperation(value = "Add a per tenant configuration for a plugin", response = TenantKeyValueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Plugin configuration uploaded successfully"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    public Response uploadPluginConfiguration(@PathParam("pluginName") final String pluginName,
+                                              final String pluginConfig,
                                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                               @HeaderParam(HDR_REASON) final String reason,
                                               @HeaderParam(HDR_COMMENT) final String comment,
@@ -209,7 +212,7 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + UPLOAD_PLUGIN_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a per tenant configuration for a plugin", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a per tenant configuration for a plugin", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getPluginConfiguration(@PathParam("pluginName") final String pluginName,
                                            @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
@@ -220,7 +223,8 @@ public class TenantResource extends JaxRsResourceBase {
     @DELETE
     @Path("/" + UPLOAD_PLUGIN_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @ApiOperation(value = "Delete a per tenant configuration for a plugin")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response deletePluginConfiguration(@PathParam("pluginName") final String pluginName,
                                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                               @HeaderParam(HDR_REASON) final String reason,
@@ -234,16 +238,16 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + UPLOAD_PER_TENANT_CONFIG + "/{keyPrefix:" + ANYTHING_PATTERN + "}" + "/" + SEARCH)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a per tenant key value based on key prefix", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a per tenant key value based on key prefix", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getAllPluginConfiguration(@PathParam("keyPrefix") final String keyPrefix,
                                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
 
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Map<String, List<String>> apiResult = tenantApi.searchTenantKeyValues(keyPrefix, tenantContext);
-        final List<TenantKeyJson> result = new ArrayList<TenantKeyJson>();
+        final List<TenantKeyValueJson> result = new ArrayList<TenantKeyValueJson>();
         for (final String cur : apiResult.keySet()) {
-            result.add(new TenantKeyJson(cur, apiResult.get(cur)));
+            result.add(new TenantKeyValueJson(cur, apiResult.get(cur)));
         }
         return Response.status(Status.OK).entity(result).build();
     }
@@ -254,8 +258,9 @@ public class TenantResource extends JaxRsResourceBase {
     @Path("/" + UPLOAD_PER_TENANT_CONFIG)
     @Consumes(TEXT_PLAIN)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a per tenant configuration (system properties)")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiOperation(value = "Add a per tenant configuration (system properties)", response = TenantKeyValueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Per tenant configuration uploaded successfully"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response uploadPerTenantConfiguration(final String perTenantConfig,
                                                  @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                  @HeaderParam(HDR_REASON) final String reason,
@@ -269,7 +274,7 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + UPLOAD_PER_TENANT_CONFIG)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a per tenant configuration (system properties)", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a per tenant configuration (system properties)", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getPerTenantConfiguration(@javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
         return getTenantKey(TenantKey.PER_TENANT_CONFIG, null, request);
@@ -279,7 +284,8 @@ public class TenantResource extends JaxRsResourceBase {
     @DELETE
     @Path("/" + UPLOAD_PER_TENANT_CONFIG)
     @ApiOperation(value = "Delete a per tenant configuration (system properties)")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response deletePerTenantConfiguration(@HeaderParam(HDR_CREATED_BY) final String createdBy,
                                               @HeaderParam(HDR_REASON) final String reason,
                                               @HeaderParam(HDR_COMMENT) final String comment,
@@ -292,10 +298,11 @@ public class TenantResource extends JaxRsResourceBase {
     @Path("/" + UPLOAD_PLUGIN_PAYMENT_STATE_MACHINE_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @Consumes(TEXT_PLAIN)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a per tenant payment state machine for a plugin")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
-    public Response uploadPluginPaymentStateMachineConfig(final String paymentStateMachineConfig,
-                                                          @PathParam("pluginName") final String pluginName,
+    @ApiOperation(value = "Add a per tenant payment state machine for a plugin", response = TenantKeyValueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Per tenant state machine uploaded successfully"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    public Response uploadPluginPaymentStateMachineConfig(@PathParam("pluginName") final String pluginName,
+                                                          final String paymentStateMachineConfig,
                                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                           @HeaderParam(HDR_REASON) final String reason,
                                                           @HeaderParam(HDR_COMMENT) final String comment,
@@ -308,7 +315,7 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + UPLOAD_PLUGIN_PAYMENT_STATE_MACHINE_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a per tenant payment state machine for a plugin", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a per tenant payment state machine for a plugin", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getPluginPaymentStateMachineConfig(@PathParam("pluginName") final String pluginName,
                                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
@@ -319,7 +326,8 @@ public class TenantResource extends JaxRsResourceBase {
     @DELETE
     @Path("/" + UPLOAD_PLUGIN_PAYMENT_STATE_MACHINE_CONFIG + "/{pluginName:" + ANYTHING_PATTERN + "}")
     @ApiOperation(value = "Delete a per tenant payment state machine for a plugin")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response deletePluginPaymentStateMachineConfig(@PathParam("pluginName") final String pluginName,
                                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                           @HeaderParam(HDR_REASON) final String reason,
@@ -333,8 +341,9 @@ public class TenantResource extends JaxRsResourceBase {
     @Path("/" + USER_KEY_VALUE + "/{keyName:" + ANYTHING_PATTERN + "}")
     @Consumes(TEXT_PLAIN)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add a per tenant user key/value")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiOperation(value = "Add a per tenant user key/value", response = TenantKeyValueJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Per tenant config uploaded successfully"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response insertUserKeyValue(@PathParam("keyName") final String key,
                                final String value,
                                @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -351,13 +360,13 @@ public class TenantResource extends JaxRsResourceBase {
     @GET
     @Path("/" + USER_KEY_VALUE + "/{keyName:" + ANYTHING_PATTERN + "}")
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a per tenant user key/value", response = TenantKeyJson.class)
+    @ApiOperation(value = "Retrieve a per tenant user key/value", response = TenantKeyValueJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response getUserKeyValue(@PathParam("keyName") final String key,
                                            @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final List<String> values = tenantApi.getTenantValuesForKey(key, tenantContext);
-        final TenantKeyJson result = new TenantKeyJson(key, values);
+        final TenantKeyValueJson result = new TenantKeyValueJson(key, values);
         return Response.status(Status.OK).entity(result).build();
     }
 
@@ -366,7 +375,8 @@ public class TenantResource extends JaxRsResourceBase {
     @DELETE
     @Path("/" + USER_KEY_VALUE + "/{keyName:" + ANYTHING_PATTERN + "}")
     @ApiOperation(value = "Delete  a per tenant user key/value")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied")})
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid tenantId supplied")})
     public Response deleteUserKeyValue(@PathParam("keyName") final String key,
                                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                               @HeaderParam(HDR_REASON) final String reason,
@@ -374,7 +384,7 @@ public class TenantResource extends JaxRsResourceBase {
                                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         tenantApi.deleteTenantKey(key, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
 
@@ -403,7 +413,7 @@ public class TenantResource extends JaxRsResourceBase {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final String tenantKey = keyPostfix != null ? key.toString() + keyPostfix : key.toString();
         final List<String> values = tenantApi.getTenantValuesForKey(tenantKey, tenantContext);
-        final TenantKeyJson result = new TenantKeyJson(tenantKey, values);
+        final TenantKeyValueJson result = new TenantKeyValueJson(tenantKey, values);
         return Response.status(Status.OK).entity(result).build();
     }
 
@@ -416,7 +426,7 @@ public class TenantResource extends JaxRsResourceBase {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final String tenantKey = keyPostfix != null ? key.toString() + keyPostfix : key.toString();
         tenantApi.deleteTenantKey(tenantKey, callContext);
-        return Response.status(Status.OK).build();
+        return Response.status(Status.NO_CONTENT).build();
     }
 
     @Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
index 8c73ca9..5a78b55 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
@@ -173,7 +173,8 @@ public class TestResource extends JaxRsResourceBase {
     @Path("/clock")
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Set the current time", response = ClockResource.class)
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid time or timezone supplied")})
+    @ApiResponses(value = {/* @ApiResponse(code = 200, message = "Successful"), */
+                           @ApiResponse(code = 400, message = "Invalid time or timezone supplied")})
     public Response setTestClockTime(@QueryParam(QUERY_REQUESTED_DT) final String requestedClockDate,
                                      @QueryParam("timeZone") final String timeZoneStr,
                                      @QueryParam("timeoutSec") @DefaultValue("5") final Long timeoutSec,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
index da16de5..cad1ac3 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
@@ -65,6 +65,7 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
 import org.killbill.billing.util.audit.AuditLogWithHistory;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
 
@@ -119,11 +120,12 @@ public class TransactionResource extends JaxRsResourceBase {
     @Path("/{transactionId:" + UUID_PATTERN + "}/")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Mark a pending payment transaction as succeeded or failed")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentId supplied"),
+    @ApiOperation(value = "Mark a pending payment transaction as succeeded or failed", response = PaymentJson.class)
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Successfully notifiy state change"),
+                           @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Account or Payment not found")})
-    public Response notifyStateChanged(final PaymentTransactionJson json,
-                                       @PathParam("transactionId") final UUID transactionId,
+    public Response notifyStateChanged(@PathParam("transactionId") final UUID transactionId,
+                                       final PaymentTransactionJson json,
                                        @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                        @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                        @HeaderParam(HDR_REASON) final String reason,
@@ -152,7 +154,7 @@ public class TransactionResource extends JaxRsResourceBase {
     @GET
     @Path("/{transactionId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment transaction custom fields", response = CustomFieldJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment transaction custom fields", response = CustomFieldJson.class, responseContainer = "List", nickname = "getTransactionCustomFields")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -165,15 +167,16 @@ public class TransactionResource extends JaxRsResourceBase {
     @Path("/{transactionId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add custom fields to payment transaction")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request,
-                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
+    @ApiOperation(value = "Add custom fields to payment transaction", response = CustomField.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Custom field created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid transaction id supplied")})
+    public Response createTransactionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  final List<CustomFieldJson> customFields,
+                                                  @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 HttpServletRequest request,
+                                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
@@ -185,13 +188,14 @@ public class TransactionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Modify custom fields to payment transaction")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response modifyCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       final List<CustomFieldJson> customFields,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid transaction id supplied")})
+    public Response modifyTransactionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  final List<CustomFieldJson> customFields,
+                                                  @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -203,13 +207,14 @@ public class TransactionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove custom fields from payment transaction")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
-                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
-                                       @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 HttpServletRequest request) throws CustomFieldApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid transaction id supplied")})
+    public Response deleteTransactionCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
+                                                  @QueryParam(QUERY_CUSTOM_FIELD) final List<UUID> customFieldList,
+                                                  @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 HttpServletRequest request) throws CustomFieldApiException {
         return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
@@ -218,12 +223,12 @@ public class TransactionResource extends JaxRsResourceBase {
     @GET
     @Path("/{transactionId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve payment transaction tags", response = TagJson.class, responseContainer = "List")
+    @ApiOperation(value = "Retrieve payment transaction tags", response = TagJson.class, responseContainer = "List", nickname = "getTransactionTags")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Payment payment = paymentApi.getPaymentByTransactionId(id, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
@@ -235,15 +240,16 @@ public class TransactionResource extends JaxRsResourceBase {
     @Path("/{transactionId:" + UUID_PATTERN + "}/" + TAGS)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Add tags to payment transaction")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response createTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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,
-                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
+    @ApiOperation(value = "Add tags to payment transaction", response = TagJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 201, message = "Tag created successfully"),
+                           @ApiResponse(code = 400, message = "Invalid transaction id supplied")})
+    public Response createTransactionTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                          final List<UUID> tagList,
+                                          @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,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
@@ -254,13 +260,14 @@ public class TransactionResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Remove tags from payment transaction")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response deleteTags(@PathParam(ID_PARAM_NAME) final UUID id,
-                               @QueryParam(QUERY_TAGS) final String tagList,
-                               @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 HttpServletRequest request) throws TagApiException {
+    @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"),
+                           @ApiResponse(code = 400, message = "Invalid transaction id supplied")})
+    public Response deleteTransactionTags(@PathParam(ID_PARAM_NAME) final UUID id,
+                                          @QueryParam(QUERY_TAG) final List<UUID> tagList,
+                                          @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 HttpServletRequest request) throws TagApiException {
         return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
index 000d28d..7aa2203 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
@@ -102,7 +102,8 @@ public class UsageResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Record usage for a subscription")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription (e.g. inactive)")})
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully recorded usage data change"),
+                           @ApiResponse(code = 400, message = "Invalid subscription (e.g. inactive)")})
     public Response recordUsage(final SubscriptionUsageRecordJson json,
                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                 @HeaderParam(HDR_REASON) final String reason,
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountEmailJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountEmailJson.java
index 71419b0..a892f8f 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountEmailJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountEmailJson.java
@@ -38,7 +38,7 @@ public class TestAccountEmailJson extends JaxrsTestSuiteNoDB {
         final String asJson = mapper.writeValueAsString(accountEmailJson);
         Assert.assertEquals(asJson, "{\"accountId\":\"" + accountId + "\"," +
                                     "\"email\":\"" + email + "\"," +
-                                    "\"auditLogs\":null}");
+                                    "\"auditLogs\":[]}");
 
         final AccountEmailJson fromJson = mapper.readValue(asJson, AccountEmailJson.class);
         Assert.assertEquals(fromJson, accountEmailJson);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
index 1e06a8e..6d484bb 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
@@ -38,7 +38,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         final String externalKey = UUID.randomUUID().toString();
         final String email = UUID.randomUUID().toString();
         final Integer billCycleDayLocal = 6;
-        final String currency = UUID.randomUUID().toString();
+        final Currency currency = Currency.USD;
         final UUID paymentMethodId = UUID.randomUUID();
         final DateTime referenceTime = new DateTime();
         final String timeZone = UUID.randomUUID().toString();
@@ -123,7 +123,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(accountJson.getLocale(), account.getLocale());
         Assert.assertEquals(accountJson.getCompany(), account.getCompanyName());
         Assert.assertEquals(accountJson.getCity(), account.getCity());
-        Assert.assertEquals(accountJson.getCurrency(), account.getCurrency().toString());
+        Assert.assertEquals(accountJson.getCurrency(), account.getCurrency());
         Assert.assertEquals(accountJson.getEmail(), account.getEmail());
         Assert.assertEquals(accountJson.getExternalKey(), account.getExternalKey());
         Assert.assertEquals(accountJson.getName(), account.getName());
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
index 626df42..72d3f5d 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
@@ -65,7 +65,7 @@ public class TestBillingExceptionJson extends JaxrsTestSuiteNoDB {
             Assert.assertFalse(exceptionJson.getStackTrace().isEmpty());
             Assert.assertEquals(exceptionJson.getStackTrace().get(0).getClassName(), TestBillingExceptionJson.class.getName());
             Assert.assertEquals(exceptionJson.getStackTrace().get(0).getMethodName(), "testFromException");
-            Assert.assertFalse(exceptionJson.getStackTrace().get(0).getNativeMethod());
+            Assert.assertFalse(exceptionJson.getStackTrace().get(0).isNativeMethod());
 
             final BillingExceptionJson exceptionJsonNoStackTrace = new BillingExceptionJson(e, false);
             Assert.assertEquals(exceptionJsonNoStackTrace.getClassName(), e.getClass().getName());
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
index 2b3e45c..2d74cb8 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
@@ -24,6 +24,11 @@ import java.util.UUID;
 
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PhaseType;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementSourceType;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.jaxrs.JaxrsTestSuiteNoDB;
 import org.killbill.billing.jaxrs.json.SubscriptionJson.EventSubscriptionJson;
 import org.testng.Assert;
@@ -43,12 +48,12 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
 
         final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID(),
-                                                                      BillingPeriod.NO_BILLING_PERIOD.toString(),
+                                                                      BillingPeriod.NO_BILLING_PERIOD,
                                                                       new LocalDate(),
                                                                       UUID.randomUUID().toString(),
                                                                       UUID.randomUUID().toString(),
                                                                       UUID.randomUUID().toString(),
-                                                                      UUID.randomUUID().toString(),
+                                                                      SubscriptionEventType.START_BILLING,
                                                                       true,
                                                                       false,
                                                                       UUID.randomUUID().toString(),
@@ -64,13 +69,13 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
                                                                    externalKey,
                                                                    new LocalDate(),
                                                                    UUID.randomUUID().toString(),
+                                                                   ProductCategory.BASE,
+                                                                   BillingPeriod.MONTHLY,
+                                                                   PhaseType.EVERGREEN,
                                                                    UUID.randomUUID().toString(),
                                                                    UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
+                                                                   EntitlementState.ACTIVE,
+                                                                   EntitlementSourceType.NATIVE,
                                                                    new LocalDate(),
                                                                    new LocalDate(),
                                                                    new LocalDate(),
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleTimelineJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleTimelineJson.java
index 18e2914..4beac86 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleTimelineJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleTimelineJson.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.jaxrs.JaxrsTestSuiteNoDB;
 import org.killbill.billing.jaxrs.json.SubscriptionJson.EventSubscriptionJson;
 import org.testng.Assert;
@@ -34,12 +35,12 @@ public class TestBundleTimelineJson extends JaxrsTestSuiteNoDB {
     @Test(groups = "fast")
     public void testJson() throws Exception {
         final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID(),
-                                                                      BillingPeriod.NO_BILLING_PERIOD.toString(),
+                                                                      BillingPeriod.NO_BILLING_PERIOD,
                                                                       new LocalDate(),
                                                                       UUID.randomUUID().toString(),
                                                                       UUID.randomUUID().toString(),
                                                                       UUID.randomUUID().toString(),
-                                                                      UUID.randomUUID().toString(),
+                                                                      SubscriptionEventType.PHASE,
                                                                       true,
                                                                       false,
                                                                       UUID.randomUUID().toString(),
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCreditJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCreditJson.java
index ad245f5..18f4373 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCreditJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCreditJson.java
@@ -34,6 +34,7 @@ public class TestCreditJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
+        final UUID creditId = UUID.randomUUID();
         final BigDecimal creditAmount = BigDecimal.TEN;
         final Currency currency = Currency.AED;
         final UUID invoiceId = UUID.randomUUID();
@@ -41,8 +42,9 @@ public class TestCreditJson extends JaxrsTestSuiteNoDB {
         final LocalDate effectiveDate = clock.getUTCToday();
         final UUID accountId = UUID.randomUUID();
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
-        final CreditJson creditJson = new CreditJson(creditAmount, currency.name(), invoiceId, invoiceNumber, effectiveDate,
+        final CreditJson creditJson = new CreditJson(creditId, creditAmount, currency, invoiceId, invoiceNumber, effectiveDate,
                                                      accountId, null, null, auditLogs);
+        Assert.assertEquals(creditJson.getCreditId(), creditId);
         Assert.assertEquals(creditJson.getEffectiveDate(), effectiveDate);
         Assert.assertEquals(creditJson.getCreditAmount(), creditAmount);
         Assert.assertEquals(creditJson.getInvoiceId(), invoiceId);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCustomFieldJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCustomFieldJson.java
index 792a1a2..30b9880 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCustomFieldJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestCustomFieldJson.java
@@ -39,7 +39,7 @@ public class TestCustomFieldJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(customFieldJson.getObjectType(), objectType);
         Assert.assertEquals(customFieldJson.getName(), name);
         Assert.assertEquals(customFieldJson.getValue(), value);
-        Assert.assertNull(customFieldJson.getAuditLogs());
+        Assert.assertEquals(customFieldJson.getAuditLogs().size(), 0);
 
         final String asJson = mapper.writeValueAsString(customFieldJson);
         final CustomFieldJson fromJson = mapper.readValue(asJson, CustomFieldJson.class);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
index 093e5ca..ca9b40f 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
@@ -28,6 +28,10 @@ import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PhaseType;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementSourceType;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.jaxrs.JaxrsTestSuiteNoDB;
 import org.killbill.billing.jaxrs.json.SubscriptionJson.EventSubscriptionJson;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
@@ -43,52 +47,50 @@ public class TestEntitlementJsonWithEvents extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final UUID accountId = UUID.randomUUID();
-        final UUID bundleId = UUID.randomUUID();
-        final UUID subscriptionId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
 
+
+
         final EventSubscriptionJson newEvent = new EventSubscriptionJson(eventId,
-                                                                         BillingPeriod.NO_BILLING_PERIOD.toString(),
+                                                                         BillingPeriod.NO_BILLING_PERIOD,
                                                                          effectiveDate.toLocalDate(),
                                                                          UUID.randomUUID().toString(),
                                                                          UUID.randomUUID().toString(),
                                                                          UUID.randomUUID().toString(),
-                                                                         SubscriptionBaseTransitionType.CREATE.toString(),
+                                                                         SubscriptionEventType.PHASE,
                                                                          false,
                                                                          true,
                                                                          UUID.randomUUID().toString(),
                                                                          UUID.randomUUID().toString(),
-                                                                         PhaseType.DISCOUNT.toString(),
+                                                                         UUID.randomUUID().toString(),
                                                                          auditLogs);
 
         final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson("foo", "bar", null, BigDecimal.TEN, BigDecimal.ONE,null);
 
-        final SubscriptionJson entitlementJsonWithEvents = new SubscriptionJson(accountId,
-                                                                                bundleId,
-                                                                                subscriptionId,
-                                                                                externalKey,
-                                                                                new LocalDate(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                UUID.randomUUID().toString(),
-                                                                                new LocalDate(),
-                                                                                new LocalDate(),
-                                                                                new LocalDate(),
-                                                                                new LocalDate(),
-                                                                                null,
-                                                                                ImmutableList.<EventSubscriptionJson>of(newEvent),
-                                                                                ImmutableList.of(priceOverride),
-                                                                                null);
-
+        final SubscriptionJson entitlementJsonWithEvents = new SubscriptionJson(UUID.randomUUID(),
+                                                                   UUID.randomUUID(),
+                                                                   UUID.randomUUID(),
+                                                                   externalKey,
+                                                                   new LocalDate(),
+                                                                   UUID.randomUUID().toString(),
+                                                                   ProductCategory.BASE,
+                                                                   BillingPeriod.MONTHLY,
+                                                                   PhaseType.EVERGREEN,
+                                                                   UUID.randomUUID().toString(),
+                                                                   UUID.randomUUID().toString(),
+                                                                   EntitlementState.ACTIVE,
+                                                                   EntitlementSourceType.NATIVE,
+                                                                   new LocalDate(),
+                                                                   new LocalDate(),
+                                                                   new LocalDate(),
+                                                                   new LocalDate(),
+                                                                   null,
+                                                                   ImmutableList.<EventSubscriptionJson>of(newEvent),
+                                                                   ImmutableList.of(priceOverride),
+                                                                   auditLogs);
         final String asJson = mapper.writeValueAsString(entitlementJsonWithEvents);
 
         final SubscriptionJson fromJson = mapper.readValue(asJson, SubscriptionJson.class);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceEmailJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceEmailJson.java
index f3a5a34..195603f 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceEmailJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceEmailJson.java
@@ -38,7 +38,7 @@ public class TestInvoiceEmailJson extends JaxrsTestSuiteNoDB {
         final String asJson = mapper.writeValueAsString(invoiceEmailJson);
         Assert.assertEquals(asJson, "{\"accountId\":\"" + accountId + "\"," +
                                     "\"isNotifiedForInvoices\":" + isNotifiedForInvoices + "," +
-                                    "\"auditLogs\":null}");
+                                    "\"auditLogs\":[]}");
 
         final InvoiceEmailJson fromJson = mapper.readValue(asJson, InvoiceEmailJson.class);
         Assert.assertEquals(fromJson, invoiceEmailJson);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
index 997eee9..668f3c7 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
@@ -46,7 +46,7 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         final String planName = UUID.randomUUID().toString();
         final String phaseName = UUID.randomUUID().toString();
         final String usageName = UUID.randomUUID().toString();
-        final String type = "FIXED";
+        final InvoiceItemType type = InvoiceItemType.FIXED;
         final String description = UUID.randomUUID().toString();
         final LocalDate startDate = clock.getUTCToday();
         final LocalDate endDate = clock.getUTCToday();
@@ -57,7 +57,7 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
                                                                     bundleId, subscriptionId, productName, planName, phaseName, usageName,
                                                                     null, null, null, null,
                                                                     type, description,
-                                                                    startDate, endDate, amount, null, currency.name(), null, null, null, auditLogs);
+                                                                    startDate, endDate, amount, null, currency, null, null, null, auditLogs);
         Assert.assertEquals(invoiceItemJson.getInvoiceItemId(), invoiceItemId);
         Assert.assertEquals(invoiceItemJson.getInvoiceId(), invoiceId);
         Assert.assertEquals(invoiceItemJson.getLinkedInvoiceItemId(), linkedInvoiceItemId);
@@ -74,7 +74,7 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceItemJson.getStartDate(), startDate);
         Assert.assertEquals(invoiceItemJson.getEndDate(), endDate);
         Assert.assertEquals(invoiceItemJson.getAmount(), amount);
-        Assert.assertEquals(invoiceItemJson.getCurrency(), currency.name());
+        Assert.assertEquals(invoiceItemJson.getCurrency(), currency);
         Assert.assertEquals(invoiceItemJson.getAuditLogs(), auditLogs);
 
         final String asJson = mapper.writeValueAsString(invoiceItemJson);
@@ -116,6 +116,6 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceItemJson.getStartDate(), invoiceItem.getStartDate());
         Assert.assertEquals(invoiceItemJson.getEndDate(), invoiceItem.getEndDate());
         Assert.assertEquals(invoiceItemJson.getAmount(), invoiceItem.getAmount());
-        Assert.assertEquals(invoiceItemJson.getCurrency(), invoiceItem.getCurrency().name());
+        Assert.assertEquals(invoiceItemJson.getCurrency(), invoiceItem.getCurrency());
     }
 }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
index df58a0e..2608fe8 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
@@ -53,7 +53,7 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         final CreditJson creditJson = createCreditJson();
         final List<CreditJson> credits = ImmutableList.<CreditJson>of(creditJson);
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
-        final InvoiceJson invoiceJsonSimple = new InvoiceJson(amount, Currency.USD.toString(), InvoiceStatus.COMMITTED.toString(),
+        final InvoiceJson invoiceJsonSimple = new InvoiceJson(amount, Currency.USD, InvoiceStatus.COMMITTED,
                                                               creditAdj, refundAdj, invoiceId, invoiceDate,
                                                               targetDate, invoiceNumber, balance, accountId, bundleKeys,
                                                               credits, null, false, null, null, auditLogs);
@@ -69,7 +69,7 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceJsonSimple.getBundleKeys(), bundleKeys);
         Assert.assertEquals(invoiceJsonSimple.getCredits(), credits);
         Assert.assertEquals(invoiceJsonSimple.getAuditLogs(), auditLogs);
-        Assert.assertEquals(invoiceJsonSimple.getStatus(), InvoiceStatus.COMMITTED.toString());
+        Assert.assertEquals(invoiceJsonSimple.getStatus(), InvoiceStatus.COMMITTED);
         Assert.assertFalse(invoiceJsonSimple.getIsParentInvoice());
 
         final String asJson = mapper.writeValueAsString(invoiceJsonSimple);
@@ -109,17 +109,18 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceJson.getAccountId(), invoice.getAccountId());
         Assert.assertEquals(invoiceJson.getBundleKeys(), bundleKeys);
         Assert.assertEquals(invoiceJson.getCredits(), credits);
-        Assert.assertNull(invoiceJson.getAuditLogs());
-        Assert.assertEquals(invoiceJson.getStatus(), InvoiceStatus.COMMITTED.toString());
+        Assert.assertEquals(invoiceJson.getAuditLogs().size(),0);
+        Assert.assertEquals(invoiceJson.getStatus(), InvoiceStatus.COMMITTED);
     }
 
     private CreditJson createCreditJson() {
         final BigDecimal creditAmount = BigDecimal.TEN;
+        final UUID creditId = UUID.randomUUID();
         final Currency currency = Currency.USD;
         final UUID invoiceId = UUID.randomUUID();
         final String invoiceNumber = UUID.randomUUID().toString();
         final LocalDate effectiveDate = clock.getUTCToday();
         final UUID accountId = UUID.randomUUID();
-        return new CreditJson(creditAmount, currency.name(), invoiceId, invoiceNumber, effectiveDate,  accountId, null, null, null);
+        return new CreditJson(creditId, creditAmount, currency, invoiceId, invoiceNumber, effectiveDate,  accountId, null, null, null);
     }
 }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
index be48168..a8bd239 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.UUID;
 
+import org.killbill.billing.ObjectType;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -34,7 +35,7 @@ public class TestTagDefinitionJson extends JaxrsTestSuiteNoDB {
         final Boolean isControlTag = true;
         final String name = UUID.randomUUID().toString();
         final String description = UUID.randomUUID().toString();
-        final ImmutableSet<String> applicableObjectTypes = ImmutableSet.<String>of(UUID.randomUUID().toString());
+        final ImmutableList<ObjectType> applicableObjectTypes = ImmutableList.of(ObjectType.TRANSACTION);
         final TagDefinitionJson tagDefinitionJson = new TagDefinitionJson(id, isControlTag, name, description, applicableObjectTypes, null);
         Assert.assertEquals(tagDefinitionJson.getId(), id);
         Assert.assertEquals(tagDefinitionJson.isControlTag(), isControlTag);

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

diff --git a/junction/pom.xml b/junction/pom.xml
index 5915349..abb20ff 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 154f9e0..73dc2cb 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -235,7 +235,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
     private int calculateBcdForTransition(final Catalog catalog, final Map<UUID, Integer> bcdCache, final SubscriptionBase baseSubscription, final SubscriptionBase subscription, final int accountBillCycleDayLocal, final EffectiveSubscriptionInternalEvent transition, final InternalTenantContext internalTenantContext)
             throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
-        final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(catalog, transition), subscription.getStartDate());
+        final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(catalog, transition), transition.getEffectiveTransitionTime(), subscription.getStartDate());
         return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, internalTenantContext, accountBillCycleDayLocal);
     }
 
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
index 186af3c..4f7e151 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project 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
@@ -286,7 +286,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     private DateTime createSubscriptionCreationEvent(final Plan nextPlan, final PlanPhase nextPhase) throws CatalogApiException {
         final DateTime now = clock.getUTCNow();
         final DateTime then = now.minusDays(1);
-        final PriceList nextPriceList = catalog.findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+        final PriceList nextPriceList = catalog.findPriceListForPlan(nextPlan.getName(), now, now);
 
         final EffectiveSubscriptionInternalEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, bunKey, then, now, null, null, null, null, null, EntitlementState.ACTIVE,
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 9436623..fa0af58 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -77,6 +77,10 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
     @BeforeMethod(groups = "fast")
     public void beforeMethod() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
+
         super.beforeMethod();
         account = Mockito.mock(Account.class);
         subscription1 = Mockito.mock(SubscriptionBase.class);

NEWS 5(+5 -0)

diff --git a/NEWS b/NEWS
index a53274a..03d294e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+0.19.15
+    Fix issue in usage billing (DETAIL mode)
+    Catalog endpoints enhancements
+    Merge fix from 0.18.x to allow to change to a plan defined in a subsequent catalog version
+
 0.19.14
     Expose and persist invoice item product name
     New history apis

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

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 769323d..7bc3332 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>

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

diff --git a/payment/pom.xml b/payment/pom.xml
index 2a02951..04558c9 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>

pom.xml 4(+2 -2)

diff --git a/pom.xml b/pom.xml
index 11416a4..fd1dd5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,10 +21,10 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.141.65</version>
+        <version>0.141.69</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.19.15-SNAPSHOT</version>
+    <version>0.19.16-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
diff --git a/profiles/killbill/pom.xml b/profiles/killbill/pom.xml
index 6d54e2f..aa493d6 100644
--- a/profiles/killbill/pom.xml
+++ b/profiles/killbill/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killbill</artifactId>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
index 7893081..8af0cde 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
@@ -34,6 +34,7 @@ import org.killbill.billing.server.filters.ResponseCorsFilter;
 import org.killbill.billing.server.modules.KillbillServerModule;
 import org.killbill.billing.server.notifications.PushNotificationListener;
 import org.killbill.billing.server.security.TenantFilter;
+import org.killbill.billing.util.nodes.KillbillVersions;
 import org.killbill.bus.api.PersistentBus;
 import org.killbill.commons.skeleton.modules.BaseServerModuleBuilder;
 import org.slf4j.Logger;
@@ -149,6 +150,7 @@ public class KillbillGuiceListener extends KillbillPlatformGuiceListener {
         beanConfig.setContact("killbilling-users@googlegroups.com");
         beanConfig.setLicense("Apache License, Version 2.0");
         beanConfig.setLicenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
+        beanConfig.setVersion(KillbillVersions.getKillbillVersion());
         beanConfig.setScan(true);
     }
 
diff --git a/profiles/killbill/src/main/resources/killbill-server.properties b/profiles/killbill/src/main/resources/killbill-server.properties
index 0a66686..b5cb949 100644
--- a/profiles/killbill/src/main/resources/killbill-server.properties
+++ b/profiles/killbill/src/main/resources/killbill-server.properties
@@ -44,13 +44,13 @@ org.killbill.persistent.bus.external.inMemory=true
 #org.killbill.persistent.bus.external.claimed=1
 #org.killbill.persistent.bus.external.nbThreads=1
 #org.killbill.persistent.bus.external.sleep=0
-#org.killbill.persistent.bus.external.queue.capacity=100
+#org.killbill.persistent.bus.external.queue.capacity=1000
 
 org.killbill.persistent.bus.main.queue.mode=STICKY_EVENTS
 org.killbill.persistent.bus.main.claimed=1
 org.killbill.persistent.bus.main.nbThreads=1
 org.killbill.persistent.bus.main.sleep=0
-org.killbill.persistent.bus.main.queue.capacity=100
+org.killbill.persistent.bus.main.queue.capacity=1000
 
 # Start KB in multi-tenant
 org.killbill.server.multitenant=true
@@ -88,7 +88,6 @@ org.killbill.payment.plugin.timeout=5s
 
 org.killbill.payment.retry.days=1,1,1
 
-
 org.killbill.notificationq.analytics.tableName=analytics_notifications
 org.killbill.notificationq.analytics.historyTableName=analytics_notifications_history
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 732e860..a34483e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -26,33 +26,66 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
-import org.killbill.billing.client.KillBillClient;
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.KillBillHttpClient;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
-import org.killbill.billing.client.model.PluginProperty;
-import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.api.gen.AccountApi;
+import org.killbill.billing.client.api.gen.AdminApi;
+import org.killbill.billing.client.api.gen.BundleApi;
+import org.killbill.billing.client.api.gen.CatalogApi;
+import org.killbill.billing.client.api.gen.CreditApi;
+import org.killbill.billing.client.api.gen.CustomFieldApi;
+import org.killbill.billing.client.api.gen.ExportApi;
+import org.killbill.billing.client.api.gen.InvoiceApi;
+import org.killbill.billing.client.api.gen.InvoiceItemApi;
+import org.killbill.billing.client.api.gen.InvoicePaymentApi;
+import org.killbill.billing.client.api.gen.NodesInfoApi;
+import org.killbill.billing.client.api.gen.OverdueApi;
+import org.killbill.billing.client.api.gen.PaymentApi;
+import org.killbill.billing.client.api.gen.PaymentGatewayApi;
+import org.killbill.billing.client.api.gen.PaymentMethodApi;
+import org.killbill.billing.client.api.gen.PaymentTransactionApi;
+import org.killbill.billing.client.api.gen.PluginInfoApi;
+import org.killbill.billing.client.api.gen.SecurityApi;
+import org.killbill.billing.client.api.gen.SubscriptionApi;
+import org.killbill.billing.client.api.gen.TagApi;
+import org.killbill.billing.client.api.gen.TagDefinitionApi;
+import org.killbill.billing.client.api.gen.TenantApi;
+import org.killbill.billing.client.api.gen.UsageApi;
 import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.gen.PluginProperty;
+import org.killbill.billing.client.model.gen.Subscription;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
 import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.tag.ControlTagType;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
 public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedDB {
 
-    protected final int DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 10;
+    protected static final ImmutableList<String> NULL_PLUGIN_NAMES = null;
+    protected static final ImmutableMap<String, String> NULL_PLUGIN_PROPERTIES = null;
+    protected static final ImmutableList<AuditLog> EMPTY_AUDIT_LOGS = ImmutableList.<AuditLog>of();
+
+
+
+    protected final long DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 10;
 
     protected static final String PLUGIN_NAME = "noop";
 
-    protected static final String DEFAULT_CURRENCY = "USD";
+    protected static final Currency DEFAULT_CURRENCY = Currency.USD;
 
     // static to be shared across test class instances (initialized once in @BeforeSuite)
     protected static CallbackServlet callbackServlet;
@@ -76,9 +109,32 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
                                                                    .withComment(comment)
                                                                    .build();
 
-    protected KillBillClient killBillClient;
     protected KillBillHttpClient killBillHttpClient;
 
+    protected AccountApi accountApi;
+    protected AdminApi adminApi;
+    protected BundleApi bundleApi;
+    protected CatalogApi catalogApi;
+    protected CreditApi creditApi;
+    protected CustomFieldApi customFieldApi;
+    protected ExportApi exportApi;
+    protected InvoiceApi invoiceApi;
+    protected InvoiceItemApi invoiceItemApi;
+    protected InvoicePaymentApi invoicePaymentApi;
+    protected NodesInfoApi nodesInfoApi;
+    protected OverdueApi overdueApi;
+    protected PaymentApi paymentApi;
+    protected PaymentGatewayApi paymentGatewayApi;
+    protected PaymentMethodApi paymentMethodApi;
+    protected PaymentTransactionApi paymentTransactionApi;
+    protected PluginInfoApi pluginInfoApi;
+    protected SecurityApi securityApi;
+    protected SubscriptionApi subscriptionApi;
+    protected TagApi tagApi;
+    protected TagDefinitionApi tagDefinitionApi;
+    protected TenantApi tenantApi;
+    protected UsageApi usageApi;
+
     protected List<PluginProperty> getPaymentMethodCCProperties() {
         final List<PluginProperty> properties = new ArrayList<PluginProperty>();
         properties.add(new PluginProperty("type", "CreditCard", false));
@@ -117,18 +173,16 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         callbackServlet.pushExpectedEvent(ExtBusEventType.ACCOUNT_CHANGE);
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
         info.setProperties(pmProperties);
-        final PaymentMethod paymentMethodJson = new PaymentMethod(null, externalkey, input.getAccountId(), true, PLUGIN_NAME, info);
-        killBillClient.createPaymentMethod(paymentMethodJson, createdBy, reason, comment);
+        final PaymentMethod paymentMethodJson = new PaymentMethod(null, externalkey, input.getAccountId(), true, PLUGIN_NAME, info, EMPTY_AUDIT_LOGS);
+        accountApi.createPaymentMethod(input.getAccountId(), paymentMethodJson, true, false, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
-        return killBillClient.getAccount(input.getExternalKey());
+        return accountApi.getAccount(input.getAccountId(), requestOptions);
     }
 
     protected Account createAccountWithExternalPaymentMethod() throws Exception {
         final Account input = createAccount();
-
         createPaymentMethod(input, true);
-
-        return killBillClient.getAccount(input.getExternalKey(), requestOptions);
+        return accountApi.getAccount(input.getAccountId(), requestOptions);
     }
 
     protected PaymentMethod createPaymentMethod(final Account input, final boolean isDefault) throws KillBillClientException {
@@ -137,8 +191,8 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         }
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
         final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUIDs.randomUUID().toString(), input.getAccountId(),
-                                                                  isDefault, ExternalPaymentProviderPlugin.PLUGIN_NAME, info);
-        final PaymentMethod paymentMethod = killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
+                                                                  isDefault, ExternalPaymentProviderPlugin.PLUGIN_NAME, info, EMPTY_AUDIT_LOGS);
+        final PaymentMethod paymentMethod = accountApi.createPaymentMethod(input.getAccountId(), paymentMethodJson, isDefault, false, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
         return paymentMethod;
     }
@@ -156,12 +210,12 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
 
     protected Account createAccountNoEvent(final UUID parentAccountId) throws KillBillClientException {
         final Account input = getAccount(parentAccountId);
-        return killBillClient.createAccount(input, createdBy, reason, comment);
+        return accountApi.createAccount(input, requestOptions);
     }
 
-    protected Subscription createEntitlement(final UUID accountId, final String bundleExternalKey, final String productName,
-                                             final ProductCategory productCategory, final BillingPeriod billingPeriod, final boolean waitCompletion) throws Exception {
-        final Account account = killBillClient.getAccount(accountId, requestOptions);
+    protected Subscription createSubscription(final UUID accountId, final String bundleExternalKey, final String productName,
+                                              final ProductCategory productCategory, final BillingPeriod billingPeriod, final boolean waitCompletion) throws Exception {
+        final Account account = accountApi.getAccount(accountId, requestOptions);
         if (account.getBillCycleDayLocal() == null || account.getBillCycleDayLocal() == 0) {
             callbackServlet.pushExpectedEvent(ExtBusEventType.ACCOUNT_CHANGE);
         }
@@ -174,8 +228,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         input.setProductCategory(productCategory);
         input.setBillingPeriod(billingPeriod);
         input.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
-
-        final Subscription subscription = killBillClient.createSubscription(input, null, null, waitCompletion ? DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC : -1, false, requestOptions);
+        final Subscription subscription = subscriptionApi.createSubscription(input, null, null, true, false, null, waitCompletion, waitCompletion ? DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC : -1L, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
 
         return subscription;
@@ -198,8 +251,8 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         assertNotNull(accountJson);
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), productName,
-                                                                ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), productName,
+                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE, ExtBusEventType.INVOICE_CREATION);
@@ -224,13 +277,13 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         assertNotNull(accountJson);
 
         callbackServlet.pushExpectedEvent(ExtBusEventType.TAG_CREATION);
-        final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.MANUAL_PAY.getId(), requestOptions);
+        final Tags accountTag = accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(ControlTagType.MANUAL_PAY.getId()), requestOptions);
         callbackServlet.assertListenerStatus();
         assertNotNull(accountTag);
         assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.MANUAL_PAY.getId());
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
@@ -247,7 +300,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         assertNotNull(accountJson);
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
@@ -260,7 +313,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         assertNotNull(accountJson);
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
@@ -287,7 +340,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     public Account getAccount(final String name, final String externalKey, final String email, final UUID parentAccountId) {
         final UUID accountId = UUID.randomUUID();
         final int length = 4;
-        final String currency = DEFAULT_CURRENCY;
+        final Currency currency = DEFAULT_CURRENCY;
         final String timeZone = "UTC";
         final String address1 = "12 rue des ecoles";
         final String address2 = "Poitier";
@@ -303,6 +356,6 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
 
         // Note: the accountId payload is ignored on account creation
         return new Account(accountId, name, length, externalKey, email, null, currency, parentAccountId, isPaymentDelegatedToParent, null, null, timeZone,
-                           address1, address2, postalCode, company, city, state, country, locale, phone, notes, false, false, null, null);
+                           address1, address2, postalCode, company, city, state, country, locale, phone, notes, false, false, null, null, EMPTY_AUDIT_LOGS);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
index 031493d..68d41a0 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
@@ -19,9 +19,7 @@
 package org.killbill.billing.jaxrs;
 
 import java.math.BigDecimal;
-import java.util.Collection;
 import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
@@ -29,16 +27,19 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
 import org.killbill.billing.client.model.Accounts;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.CustomField;
+import org.killbill.billing.client.model.AuditLogs;
+import org.killbill.billing.client.model.CustomFields;
 import org.killbill.billing.client.model.InvoicePayments;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
 import org.killbill.billing.client.model.PaymentMethods;
-import org.killbill.billing.client.model.Tag;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.CustomField;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.gen.Tag;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
@@ -49,7 +50,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 import static org.testng.Assert.assertEquals;
@@ -89,7 +90,7 @@ public class TestAccount extends TestJaxrsBase {
     public void testEmptyAccount() throws Exception {
         final Account emptyAccount = new Account();
 
-        final Account account = killBillClient.createAccount(emptyAccount, requestOptions);
+        final Account account = accountApi.createAccount(emptyAccount, requestOptions);
         Assert.assertNotNull(account.getExternalKey());
         Assert.assertNull(account.getName());
         Assert.assertNull(account.getEmail());
@@ -101,12 +102,12 @@ public class TestAccount extends TestJaxrsBase {
         final Account inputWithNoExternalKey = getAccount(UUID.randomUUID().toString(), null, UUID.randomUUID().toString());
         Assert.assertNull(inputWithNoExternalKey.getExternalKey());
 
-        final Account account = killBillClient.createAccount(inputWithNoExternalKey, requestOptions);
+        final Account account = accountApi.createAccount(inputWithNoExternalKey, requestOptions);
         Assert.assertNotNull(account.getExternalKey());
 
         final Account inputWithSameExternalKey = getAccount(UUID.randomUUID().toString(), account.getExternalKey(), UUID.randomUUID().toString());
         try {
-            killBillClient.createAccount(inputWithSameExternalKey, requestOptions);
+            accountApi.createAccount(inputWithSameExternalKey, requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getBillingException().getCode(), (Integer) ErrorCode.ACCOUNT_ALREADY_EXISTS.getCode());
@@ -118,7 +119,7 @@ public class TestAccount extends TestJaxrsBase {
         final Account input = createAccount();
 
         // Retrieves by external key
-        final Account retrievedAccount = killBillClient.getAccount(input.getExternalKey(), requestOptions);
+        final Account retrievedAccount = accountApi.getAccountByKey(input.getExternalKey(), requestOptions);
         Assert.assertTrue(retrievedAccount.equals(input));
 
         // Try search endpoint
@@ -127,11 +128,12 @@ public class TestAccount extends TestJaxrsBase {
         // Update Account
         final Account newInput = new Account(input.getAccountId(),
                                              "zozo", 4, input.getExternalKey(), "rr@google.com", 18,
-                                             "USD", null, false, null, null, "UTC",
+                                             Currency.USD, null, false, null, null, "UTC",
                                              "bl1", "bh2", "", "", "ca", "San Francisco", "usa", "en", "415-255-2991",
-                                             "notes", false, false, null, null);
+                                             "notes", false, false, null, null, EMPTY_AUDIT_LOGS);
 
-        final Account updatedAccount = killBillClient.updateAccount(newInput, requestOptions);
+        accountApi.updateAccount(input.getAccountId(), newInput, requestOptions);
+        final Account updatedAccount = accountApi.getAccount(input.getAccountId(), requestOptions);
         // referenceTime is set automatically by system, no way to guess it
         newInput.setReferenceTime(updatedAccount.getReferenceTime());
         Assert.assertTrue(updatedAccount.equals(newInput));
@@ -155,7 +157,6 @@ public class TestAccount extends TestJaxrsBase {
         Assert.assertEquals(input.getCountry(), "France");
         Assert.assertEquals(input.getLocale(), "fr");
 
-
         // Set notes to something else
         final Account newInput = new Account(input.getAccountId(),
                                              null,
@@ -182,11 +183,12 @@ public class TestAccount extends TestJaxrsBase {
                                              null,
                                              null,
                                              null,
-                                             null);
-
+                                             null,
+                                             EMPTY_AUDIT_LOGS);
 
         // Update notes, all other fields remaining the same (value set to null but treatNullAsReset defaults to false)
-        Account updatedAccount = killBillClient.updateAccount(newInput, requestOptions);
+        accountApi.updateAccount(newInput.getAccountId(), newInput, requestOptions);
+        Account updatedAccount = accountApi.getAccount(input.getAccountId(), requestOptions);
 
         Assert.assertNotNull(updatedAccount.getExternalKey());
         Assert.assertNotNull(updatedAccount.getNotes());
@@ -201,7 +203,8 @@ public class TestAccount extends TestJaxrsBase {
 
         // Reset notes, all other fields remaining the same
         updatedAccount.setNotes(null);
-        updatedAccount = killBillClient.updateAccount(updatedAccount, true, requestOptions);
+        accountApi.updateAccount(updatedAccount.getAccountId(), updatedAccount, true, requestOptions);
+        updatedAccount = accountApi.getAccount(input.getAccountId(), requestOptions);
 
         Assert.assertNotNull(updatedAccount.getExternalKey());
         Assert.assertNull(updatedAccount.getNotes());
@@ -214,12 +217,11 @@ public class TestAccount extends TestJaxrsBase {
         Assert.assertEquals(updatedAccount.getLocale(), "fr");
     }
 
-
     @Test(groups = "slow", description = "Can retrieve the account balance")
     public void testAccountWithBalance() throws Exception {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
-        final Account accountWithBalance = killBillClient.getAccount(accountJson.getAccountId(), true, false, requestOptions);
+        final Account accountWithBalance = accountApi.getAccount(accountJson.getAccountId(), true, false, AuditLevel.NONE, requestOptions);
         final BigDecimal accountBalance = accountWithBalance.getAccountBalance();
         Assert.assertTrue(accountBalance.compareTo(BigDecimal.ZERO) > 0);
     }
@@ -227,14 +229,12 @@ public class TestAccount extends TestJaxrsBase {
     @Test(groups = "slow", description = "Cannot update a non-existent account")
     public void testUpdateNonExistentAccount() throws Exception {
         final Account input = getAccount();
-
-        Assert.assertNull(killBillClient.updateAccount(input, requestOptions));
+        accountApi.updateAccount(input.getAccountId(), input, requestOptions);
     }
 
     @Test(groups = "slow", description = "Cannot retrieve non-existent account")
     public void testAccountNonExistent() throws Exception {
-        Assert.assertNull(killBillClient.getAccount(UUID.randomUUID(), requestOptions));
-        Assert.assertNull(killBillClient.getAccount(UUID.randomUUID().toString(), requestOptions));
+        Assert.assertNull(accountApi.getAccount(UUID.randomUUID(), requestOptions));
     }
 
     @Test(groups = "slow", description = "Can CRUD payment methods")
@@ -244,50 +244,50 @@ public class TestAccount extends TestJaxrsBase {
 
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
         info.setProperties(getPaymentMethodCCProperties());
-        PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), true, PLUGIN_NAME, info);
-        final PaymentMethod paymentMethodCC = killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
-        assertTrue(paymentMethodCC.getIsDefault());
+        PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), true, PLUGIN_NAME, info, EMPTY_AUDIT_LOGS);
+        final PaymentMethod paymentMethodCC = accountApi.createPaymentMethod(accountJson.getAccountId(), paymentMethodJson, true, false, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        assertTrue(paymentMethodCC.isDefault());
 
         //
         // Add another payment method
         //
         final PaymentMethodPluginDetail info2 = new PaymentMethodPluginDetail();
         info2.setProperties(getPaymentMethodPaypalProperties());
-        paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), false, PLUGIN_NAME, info2);
-        final PaymentMethod paymentMethodPP = killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
-        assertFalse(paymentMethodPP.getIsDefault());
+        paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), false, PLUGIN_NAME, info2, EMPTY_AUDIT_LOGS);
+        final PaymentMethod paymentMethodPP = accountApi.createPaymentMethod(accountJson.getAccountId(), paymentMethodJson, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        assertFalse(paymentMethodPP.isDefault());
 
         //
         // FETCH ALL PAYMENT METHODS
         //
-        List<PaymentMethod> paymentMethods = killBillClient.getPaymentMethodsForAccount(accountJson.getAccountId(), requestOptions);
+        List<PaymentMethod> paymentMethods = accountApi.getPaymentMethodsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentMethods.size(), 2);
 
         //
         // CHANGE DEFAULT
         //
-        assertTrue(killBillClient.getPaymentMethod(paymentMethodCC.getPaymentMethodId(), requestOptions).getIsDefault());
-        assertFalse(killBillClient.getPaymentMethod(paymentMethodPP.getPaymentMethodId(), requestOptions).getIsDefault());
-        killBillClient.updateDefaultPaymentMethod(accountJson.getAccountId(), paymentMethodPP.getPaymentMethodId(), requestOptions);
-        assertTrue(killBillClient.getPaymentMethod(paymentMethodPP.getPaymentMethodId(), requestOptions).getIsDefault());
-        assertFalse(killBillClient.getPaymentMethod(paymentMethodCC.getPaymentMethodId(), requestOptions).getIsDefault());
+        assertTrue(paymentMethodApi.getPaymentMethod(paymentMethodCC.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions).isDefault());
+        assertFalse(paymentMethodApi.getPaymentMethod(paymentMethodPP.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions).isDefault());
+        accountApi.setDefaultPaymentMethod(accountJson.getAccountId(), paymentMethodPP.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        assertTrue(paymentMethodApi.getPaymentMethod(paymentMethodPP.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions).isDefault());
+        assertFalse(paymentMethodApi.getPaymentMethod(paymentMethodCC.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions).isDefault());
 
         //
         // DELETE NON DEFAULT PM
         //
-        killBillClient.deletePaymentMethod(paymentMethodCC.getPaymentMethodId(), false, false, requestOptions);
+        paymentMethodApi.deletePaymentMethod(paymentMethodCC.getPaymentMethodId(), false, false, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         //
         // FETCH ALL PAYMENT METHODS
         //
-        paymentMethods = killBillClient.getPaymentMethodsForAccount(accountJson.getAccountId(), requestOptions);
+        paymentMethods = accountApi.getPaymentMethodsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentMethods.size(), 1);
 
         //
         // DELETE DEFAULT PAYMENT METHOD (without special flag first)
         //
         try {
-            killBillClient.deletePaymentMethod(paymentMethodPP.getPaymentMethodId(), false, false, requestOptions);
+            paymentMethodApi.deletePaymentMethod(paymentMethodPP.getPaymentMethodId(), false, false, NULL_PLUGIN_PROPERTIES, requestOptions);
             fail();
         } catch (final KillBillClientException e) {
         }
@@ -295,17 +295,17 @@ public class TestAccount extends TestJaxrsBase {
         //
         // RETRY TO DELETE DEFAULT PAYMENT METHOD (with special flag this time)
         //
-        killBillClient.deletePaymentMethod(paymentMethodPP.getPaymentMethodId(), true, false, requestOptions);
+        paymentMethodApi.deletePaymentMethod(paymentMethodPP.getPaymentMethodId(), true, false, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // CHECK ACCOUNT IS NOW AUTO_PAY_OFF
-        final List<Tag> tagsJson = killBillClient.getAccountTags(accountJson.getAccountId(), requestOptions);
+        final List<Tag> tagsJson = accountApi.getAccountTags(accountJson.getAccountId(), requestOptions);
         Assert.assertEquals(tagsJson.size(), 1);
         final Tag tagJson = tagsJson.get(0);
         Assert.assertEquals(tagJson.getTagDefinitionName(), "AUTO_PAY_OFF");
         Assert.assertEquals(tagJson.getTagDefinitionId(), new UUID(0, 1));
 
         // FETCH ACCOUNT AGAIN AND CHECK THERE IS NO DEFAULT PAYMENT METHOD SET
-        final Account updatedAccount = killBillClient.getAccount(accountJson.getAccountId(), requestOptions);
+        final Account updatedAccount = accountApi.getAccount(accountJson.getAccountId(), requestOptions);
         Assert.assertEquals(updatedAccount.getAccountId(), accountJson.getAccountId());
         Assert.assertNull(updatedAccount.getPaymentMethodId());
 
@@ -313,8 +313,9 @@ public class TestAccount extends TestJaxrsBase {
         // FINALLY TRY TO REMOVE AUTO_PAY_OFF WITH NO DEFAULT PAYMENT METHOD ON ACCOUNT
         //
         try {
-            killBillClient.deleteAccountTag(accountJson.getAccountId(), new UUID(0, 1), requestOptions);
+            accountApi.deleteAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(new UUID(0, 1)), requestOptions);
         } catch (final KillBillClientException e) {
+            Assert.assertTrue(e.getBillingException().getCode() == ErrorCode.TAG_CANNOT_BE_REMOVED.getCode());
         }
     }
 
@@ -323,7 +324,7 @@ public class TestAccount extends TestJaxrsBase {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Verify payments
-        final InvoicePayments objFromJson = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final InvoicePayments objFromJson = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(objFromJson.size(), 1);
     }
 
@@ -334,19 +335,19 @@ public class TestAccount extends TestJaxrsBase {
         final UUID autoPayOffId = new UUID(0, 1);
 
         // Add a tag
-        killBillClient.createAccountTag(input.getAccountId(), autoPayOffId, requestOptions);
+        accountApi.createAccountTags(input.getAccountId(), ImmutableList.<UUID>of(autoPayOffId), requestOptions);
 
         // Retrieves all tags
-        final List<Tag> tags1 = killBillClient.getAccountTags(input.getAccountId(), AuditLevel.FULL, requestOptions);
+        final List<Tag> tags1 = accountApi.getAccountTags(input.getAccountId(), false, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(tags1.size(), 1);
         Assert.assertEquals(tags1.get(0).getTagDefinitionId(), autoPayOffId);
 
         // Verify adding the same tag a second time doesn't do anything
-        killBillClient.createAccountTag(input.getAccountId(), autoPayOffId, requestOptions);
+        accountApi.createAccountTags(input.getAccountId(), ImmutableList.<UUID>of(autoPayOffId), requestOptions);
 
         // Retrieves all tags again
-        killBillClient.createAccountTag(input.getAccountId(), autoPayOffId, requestOptions);
-        final List<Tag> tags2 = killBillClient.getAccountTags(input.getAccountId(), AuditLevel.FULL, requestOptions);
+        accountApi.createAccountTags(input.getAccountId(), ImmutableList.<UUID>of(autoPayOffId), requestOptions);
+        final List<Tag> tags2 = accountApi.getAccountTags(input.getAccountId(), true, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(tags2, tags1);
 
         // Verify audit logs
@@ -365,20 +366,20 @@ public class TestAccount extends TestJaxrsBase {
         final Account accountJson = createAccount();
         assertNotNull(accountJson);
 
-        final Collection<CustomField> customFields = new LinkedList<CustomField>();
-        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "1", "value1", null));
-        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "2", "value2", null));
-        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "3", "value3", null));
+        final CustomFields customFields = new CustomFields();
+        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "1", "value1", EMPTY_AUDIT_LOGS));
+        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "2", "value2", EMPTY_AUDIT_LOGS));
+        customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "3", "value3", EMPTY_AUDIT_LOGS));
 
-        killBillClient.createAccountCustomFields(accountJson.getAccountId(), customFields, requestOptions);
+        accountApi.createAccountCustomFields(accountJson.getAccountId(), customFields, requestOptions);
 
-        final List<CustomField> accountCustomFields = killBillClient.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
+        final List<CustomField> accountCustomFields = accountApi.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
         assertEquals(accountCustomFields.size(), 3);
 
         // Delete all custom fields for account
-        killBillClient.deleteAccountCustomFields(accountJson.getAccountId(), requestOptions);
+        accountApi.deleteAccountCustomFields(accountJson.getAccountId(), null, requestOptions);
 
-        final List<CustomField> remainingCustomFields = killBillClient.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
+        final List<CustomField> remainingCustomFields = accountApi.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
         assertEquals(remainingCustomFields.size(), 0);
     }
 
@@ -386,28 +387,28 @@ public class TestAccount extends TestJaxrsBase {
     public void testRefreshPaymentMethods() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod("someExternalKey");
 
-        final PaymentMethods paymentMethodsBeforeRefreshing = killBillClient.getPaymentMethodsForAccount(account.getAccountId(), requestOptions);
+        final PaymentMethods paymentMethodsBeforeRefreshing = accountApi.getPaymentMethodsForAccount(account.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentMethodsBeforeRefreshing.size(), 1);
         assertEquals(paymentMethodsBeforeRefreshing.get(0).getExternalKey(), "someExternalKey");
 
         // WITH NAME OF AN EXISTING PLUGIN
-        killBillClient.refreshPaymentMethods(account.getAccountId(), PLUGIN_NAME, ImmutableMap.<String, String>of(), requestOptions);
+        accountApi.refreshPaymentMethods(account.getAccountId(), PLUGIN_NAME, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final PaymentMethods paymentMethodsAfterExistingPluginCall = killBillClient.getPaymentMethodsForAccount(account.getAccountId(), requestOptions);
+        final PaymentMethods paymentMethodsAfterExistingPluginCall = accountApi.getPaymentMethodsForAccount(account.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
         assertEquals(paymentMethodsAfterExistingPluginCall.size(), 1);
         assertEquals(paymentMethodsAfterExistingPluginCall.get(0).getExternalKey(), "someExternalKey");
 
         // WITHOUT PLUGIN NAME
-        killBillClient.refreshPaymentMethods(account.getAccountId(), ImmutableMap.<String, String>of(), requestOptions);
+        accountApi.refreshPaymentMethods(account.getAccountId(), PLUGIN_NAME, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final PaymentMethods paymentMethodsAfterNoPluginNameCall = killBillClient.getPaymentMethodsForAccount(account.getAccountId(), requestOptions);
+        final PaymentMethods paymentMethodsAfterNoPluginNameCall = accountApi.getPaymentMethodsForAccount(account.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentMethodsAfterNoPluginNameCall.size(), 1);
         assertEquals(paymentMethodsAfterNoPluginNameCall.get(0).getExternalKey(), "someExternalKey");
 
         // WITH WRONG PLUGIN NAME
         try {
-            killBillClient.refreshPaymentMethods(account.getAccountId(), "GreatestPluginEver", ImmutableMap.<String, String>of(), requestOptions);
+            accountApi.refreshPaymentMethods(account.getAccountId(), "GreatestPluginEver", NULL_PLUGIN_PROPERTIES, requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getBillingException().getCode(), (Integer) ErrorCode.PAYMENT_NO_SUCH_PAYMENT_PLUGIN.getCode());
@@ -420,10 +421,10 @@ public class TestAccount extends TestJaxrsBase {
             createAccount();
         }
 
-        final Accounts allAccounts = killBillClient.getAccounts(requestOptions);
+        final Accounts allAccounts = accountApi.getAccounts(requestOptions);
         Assert.assertEquals(allAccounts.size(), 5);
 
-        Accounts page = killBillClient.getAccounts(0L, 1L, requestOptions);
+        Accounts page = accountApi.getAccounts(0L, 1L, false, false, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
@@ -450,14 +451,14 @@ public class TestAccount extends TestJaxrsBase {
 
         // Search by external key.
         // Note: we will always find a match since we don't update it
-        final List<Account> accountsByExternalKey = killBillClient.searchAccounts(input.getExternalKey(), requestOptions);
+        final List<Account> accountsByExternalKey = accountApi.searchAccounts(input.getExternalKey(), requestOptions);
         Assert.assertEquals(accountsByExternalKey.size(), 1);
         Assert.assertEquals(accountsByExternalKey.get(0).getAccountId(), input.getAccountId());
         Assert.assertEquals(accountsByExternalKey.get(0).getExternalKey(), input.getExternalKey());
     }
 
     private void doSearchAccount(final String key, @Nullable final Account output) throws Exception {
-        final List<Account> accountsByKey = killBillClient.searchAccounts(key, requestOptions);
+        final List<Account> accountsByKey = accountApi.searchAccounts(key, requestOptions);
         if (output == null) {
             Assert.assertEquals(accountsByKey.size(), 0);
         } else {
@@ -474,13 +475,13 @@ public class TestAccount extends TestJaxrsBase {
         final Account childInput = getAccount();
         childInput.setParentAccountId(parentAccount.getAccountId());
         childInput.setIsPaymentDelegatedToParent(true);
-        final Account childAccount = killBillClient.createAccount(childInput, requestOptions);
+        final Account childAccount = accountApi.createAccount(childInput, requestOptions);
 
         // Retrieves child account by external key
-        final Account retrievedAccount = killBillClient.getAccount(childAccount.getExternalKey(), requestOptions);
+        final Account retrievedAccount = accountApi.getAccountByKey(childAccount.getExternalKey(), requestOptions);
         Assert.assertTrue(retrievedAccount.equals(childAccount));
         Assert.assertEquals(retrievedAccount.getParentAccountId(), parentAccount.getAccountId());
-        Assert.assertTrue(retrievedAccount.getIsPaymentDelegatedToParent());
+        Assert.assertTrue(retrievedAccount.isPaymentDelegatedToParent());
     }
 
     @Test(groups = "slow", description = "retrieve children accounts by parent account id")
@@ -491,17 +492,17 @@ public class TestAccount extends TestJaxrsBase {
         final Account childInput = getAccount();
         childInput.setParentAccountId(parentAccount.getAccountId());
         childInput.setIsPaymentDelegatedToParent(true);
-        Account childAccount = killBillClient.createAccount(childInput, requestOptions);
-        childAccount = killBillClient.getAccount(childAccount.getAccountId(), true, true, requestOptions);
+        Account childAccount = accountApi.createAccount(childInput, requestOptions);
+        childAccount = accountApi.getAccount(childAccount.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
 
         final Account childInput2 = getAccount();
         childInput2.setParentAccountId(parentAccount.getAccountId());
         childInput2.setIsPaymentDelegatedToParent(true);
-        Account childAccount2 = killBillClient.createAccount(childInput2, requestOptions);
-        childAccount2 = killBillClient.getAccount(childAccount2.getAccountId(), true, true, requestOptions);
+        Account childAccount2 = accountApi.createAccount(childInput2, requestOptions);
+        childAccount2 = accountApi.getAccount(childAccount2.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
 
         // Retrieves children accounts by parent account id
-        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(parentAccount.getAccountId(), true, true, requestOptions);
+        final Accounts childrenAccounts = accountApi.getChildrenAccounts(parentAccount.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(childrenAccounts.size(), 2);
 
         Assert.assertTrue(childrenAccounts.get(0).equals(childAccount));
@@ -512,37 +513,27 @@ public class TestAccount extends TestJaxrsBase {
     public void testEmptyGetChildrenAccounts() throws Exception {
 
         // Retrieves children accounts by parent account id
-        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(UUID.randomUUID(), false, false, requestOptions);
+        final Accounts childrenAccounts = accountApi.getChildrenAccounts(UUID.randomUUID(), false, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(childrenAccounts.size(), 0);
 
     }
-
-    @Test(groups = "slow", description = "retrieve an empty children accounts list by a null id")
-    public void testGetChildrenAccountsByNullId() throws Exception {
-
-        // Retrieves children accounts by parent account id
-        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(null, true, true, requestOptions);
-        Assert.assertEquals(childrenAccounts.size(), 0);
-
-    }
-
     @Test(groups = "slow", description = "retrieve account logs")
     public void testGetAccountAuditLogs() throws Exception {
         final Account accountJson = createAccount();
         assertNotNull(accountJson);
 
         // generate more log data
-        final Collection<CustomField> customFields = new LinkedList<CustomField>();
+        final CustomFields customFields = new CustomFields();
         customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "1", "value1", null));
         customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "2", "value2", null));
         customFields.add(new CustomField(null, accountJson.getAccountId(), ObjectType.ACCOUNT, "3", "value3", null));
 
-        killBillClient.createAccountCustomFields(accountJson.getAccountId(), customFields, requestOptions);
+        accountApi.createAccountCustomFields(accountJson.getAccountId(), customFields, requestOptions);
 
-        final List<CustomField> accountCustomFields = killBillClient.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
+        final CustomFields accountCustomFields = accountApi.getAccountCustomFields(accountJson.getAccountId(), requestOptions);
         assertEquals(accountCustomFields.size(), 3);
 
-        final List<AuditLog> auditLogsJson = killBillClient.getAccountAuditLogs(accountJson.getAccountId());
+        final AuditLogs auditLogsJson = accountApi.getAccountAuditLogs(accountJson.getAccountId(), requestOptions);
         assertEquals(auditLogsJson.size(), 4);
         assertEquals(auditLogsJson.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(auditLogsJson.get(0).getObjectType(), ObjectType.ACCOUNT);
@@ -567,22 +558,21 @@ public class TestAccount extends TestJaxrsBase {
         assertNotNull(accountJson);
 
         // Update Account
-        final Account newInput = new Account(accountJson.getAccountId(),
-                                             "zozo", 4, accountJson.getExternalKey(), "rr@google.com", 18,
-                                             "USD", null, false, null, null, "UTC",
-                                             "bl1", "bh2", "", "", "ca", "San Francisco", "usa", "en", "415-255-2991",
-                                             "notes", false, false, null, null);
+        final Account newInput = new Account()
+                .setAccountId(accountJson.getAccountId())
+                .setExternalKey(accountJson.getExternalKey())
+                .setName("zozo");
 
-        final Account updatedAccount = killBillClient.updateAccount(newInput, requestOptions);
 
+        accountApi.updateAccount(accountJson.getAccountId(), newInput, requestOptions);
 
-        final List<AuditLog> auditLogWithHistories = killBillClient.getAccountAuditLogsWithHistory(accountJson.getAccountId());
+        final List<AuditLog> auditLogWithHistories = accountApi.getAccountAuditLogsWithHistory(accountJson.getAccountId(), requestOptions);
         assertEquals(auditLogWithHistories.size(), 2);
         assertEquals(auditLogWithHistories.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(auditLogWithHistories.get(0).getObjectType(), ObjectType.ACCOUNT);
         assertEquals(auditLogWithHistories.get(0).getObjectId(), accountJson.getAccountId());
 
-        final LinkedHashMap history1 = (LinkedHashMap) auditLogWithHistories.get(0).getHistory();
+        final LinkedHashMap<String, Object> history1 = (LinkedHashMap<String, Object>) auditLogWithHistories.get(0).getHistory();
         assertNotNull(history1);
         assertEquals(history1.get("externalKey"), accountJson.getExternalKey());
         assertEquals(history1.get("name"), accountJson.getName());
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmail.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmail.java
index 29b6613..0941f0a 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmail.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmail.java
@@ -23,9 +23,9 @@ import java.util.List;
 import java.util.UUID;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AccountEmail;
-import org.killbill.billing.client.model.AuditLog;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AccountEmail;
+import org.killbill.billing.client.model.gen.AuditLog;
 import org.killbill.billing.util.audit.ChangeType;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -42,27 +42,27 @@ public class TestAccountEmail extends TestJaxrsBase {
 
         final String email1 = UUID.randomUUID().toString();
         final String email2 = UUID.randomUUID().toString();
-        final AccountEmail accountEmailJson1 = new AccountEmail(accountId, email1);
-        final AccountEmail accountEmailJson2 = new AccountEmail(accountId, email2);
+        final AccountEmail accountEmailJson1 = new AccountEmail(accountId, email1, null);
+        final AccountEmail accountEmailJson2 = new AccountEmail(accountId, email2, null);
 
         // Verify the initial state
-        final List<AccountEmail> firstEmails = killBillClient.getEmailsForAccount(accountId);
+        final List<AccountEmail> firstEmails = accountApi.getEmails(accountId, requestOptions);
         Assert.assertEquals(firstEmails.size(), 0);
 
         // Add an email
-        killBillClient.addEmailToAccount(accountEmailJson1, createdBy, reason, comment);
+        accountApi.addEmail(accountId, accountEmailJson1, requestOptions);
 
         // Verify we can retrieve it
-        final List<AccountEmail> secondEmails = killBillClient.getEmailsForAccount(accountId);
+        final List<AccountEmail> secondEmails = accountApi.getEmails(accountId, requestOptions);
         Assert.assertEquals(secondEmails.size(), 1);
         Assert.assertEquals(secondEmails.get(0).getAccountId(), accountId);
         Assert.assertEquals(secondEmails.get(0).getEmail(), email1);
 
         // Add another email
-        killBillClient.addEmailToAccount(accountEmailJson2, createdBy, reason, comment);
+        accountApi.addEmail(accountId, accountEmailJson2, requestOptions);
 
         // Verify we can retrieve both
-        final List<AccountEmail> thirdEmails = killBillClient.getEmailsForAccount(accountId);
+        final List<AccountEmail> thirdEmails = accountApi.getEmails(accountId, requestOptions);
         Assert.assertEquals(thirdEmails.size(), 2);
         Assert.assertEquals(thirdEmails.get(0).getAccountId(), accountId);
         Assert.assertEquals(thirdEmails.get(1).getAccountId(), accountId);
@@ -70,17 +70,17 @@ public class TestAccountEmail extends TestJaxrsBase {
         Assert.assertTrue(thirdEmails.get(1).getEmail().equals(email1) || thirdEmails.get(1).getEmail().equals(email2));
 
         // Delete the first email
-        killBillClient.removeEmailFromAccount(accountEmailJson1, createdBy, reason, comment);
+        accountApi.removeEmail(accountId, accountEmailJson1.getEmail(), requestOptions);
 
         // Verify it has been deleted
-        final List<AccountEmail> fourthEmails = killBillClient.getEmailsForAccount(accountId);
+        final List<AccountEmail> fourthEmails = accountApi.getEmails(accountId, requestOptions);
         Assert.assertEquals(fourthEmails.size(), 1);
         Assert.assertEquals(fourthEmails.get(0).getAccountId(), accountId);
         Assert.assertEquals(fourthEmails.get(0).getEmail(), email2);
 
         // Try to add the same email
-        killBillClient.addEmailToAccount(accountEmailJson2, createdBy, reason, comment);
-        Assert.assertEquals(killBillClient.getEmailsForAccount(accountId), fourthEmails);
+        accountApi.addEmail(accountId, accountEmailJson2, requestOptions);
+        Assert.assertEquals(accountApi.getEmails(accountId, requestOptions), fourthEmails);
     }
 
     @Test(groups = "slow", description = "retrieve account logs")
@@ -89,16 +89,15 @@ public class TestAccountEmail extends TestJaxrsBase {
         assertNotNull(accountJson);
 
         final String email1 = UUID.randomUUID().toString();
-        final AccountEmail accountEmailJson1 = new AccountEmail(accountJson.getAccountId(), email1);
+        final AccountEmail accountEmailJson1 = new AccountEmail(accountJson.getAccountId(), email1, EMPTY_AUDIT_LOGS);
 
         // Add an email
-        killBillClient.addEmailToAccount(accountEmailJson1, requestOptions);
+        accountApi.addEmail(accountJson.getAccountId(), accountEmailJson1, requestOptions);
 
         // get all audit for the account
-        final List<AuditLog> auditLogsJson = killBillClient.getAccountAuditLogs(accountJson.getAccountId());
+        final List<AuditLog> auditLogsJson = accountApi.getAccountAuditLogs(accountJson.getAccountId(), requestOptions);
         Assert.assertEquals(auditLogsJson.size(), 2);
-
-        final List<AuditLog> emailAuditLogWithHistories = killBillClient.getAccountEmailAuditLogsWithHistory(accountJson.getAccountId(), auditLogsJson.get(0).getObjectId());
+        final List<AuditLog> emailAuditLogWithHistories = accountApi.getAccountEmailAuditLogsWithHistory(accountJson.getAccountId(), auditLogsJson.get(0).getObjectId(), requestOptions);
         assertEquals(emailAuditLogWithHistories.size(), 1);
         assertEquals(emailAuditLogWithHistories.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(emailAuditLogWithHistories.get(0).getObjectType(), ObjectType.ACCOUNT_EMAIL);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmailNotifications.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmailNotifications.java
index fb0af86..29663f4 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmailNotifications.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountEmailNotifications.java
@@ -20,8 +20,8 @@ package org.killbill.billing.jaxrs;
 
 import java.util.UUID;
 
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.InvoiceEmail;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.InvoiceEmail;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -32,27 +32,27 @@ public class TestAccountEmailNotifications extends TestJaxrsBase {
         final Account input = createAccount();
         final UUID accountId = input.getAccountId();
 
-        final InvoiceEmail invoiceEmailJsonWithNotifications = new InvoiceEmail(accountId, true);
-        final InvoiceEmail invoiceEmailJsonWithoutNotifications = new InvoiceEmail(accountId, false);
+        final InvoiceEmail invoiceEmailJsonWithNotifications = new InvoiceEmail(accountId, true, null);
+        final InvoiceEmail invoiceEmailJsonWithoutNotifications = new InvoiceEmail(accountId, false, null);
 
         // Verify the initial state
-        final InvoiceEmail firstInvoiceEmailJson = killBillClient.getEmailNotificationsForAccount(accountId);
+        final InvoiceEmail firstInvoiceEmailJson = accountApi.getEmailNotificationsForAccount(accountId, requestOptions);
         Assert.assertEquals(firstInvoiceEmailJson.getAccountId(), accountId);
         Assert.assertFalse(firstInvoiceEmailJson.isNotifiedForInvoices());
 
         // Enable email notifications
-        killBillClient.updateEmailNotificationsForAccount(invoiceEmailJsonWithNotifications, createdBy, reason, comment);
+        accountApi.setEmailNotificationsForAccount(accountId, invoiceEmailJsonWithNotifications, requestOptions);
 
         // Verify we can retrieve it
-        final InvoiceEmail secondInvoiceEmailJson = killBillClient.getEmailNotificationsForAccount(accountId);
+        final InvoiceEmail secondInvoiceEmailJson = accountApi.getEmailNotificationsForAccount(accountId, requestOptions);
         Assert.assertEquals(secondInvoiceEmailJson.getAccountId(), accountId);
         Assert.assertTrue(secondInvoiceEmailJson.isNotifiedForInvoices());
 
         // Disable email notifications
-        killBillClient.updateEmailNotificationsForAccount(invoiceEmailJsonWithoutNotifications, createdBy, reason, comment);
+        accountApi.setEmailNotificationsForAccount(accountId, invoiceEmailJsonWithoutNotifications, requestOptions);
 
         // Verify we can retrieve it
-        final InvoiceEmail thirdInvoiceEmailJson = killBillClient.getEmailNotificationsForAccount(accountId);
+        final InvoiceEmail thirdInvoiceEmailJson = accountApi.getEmailNotificationsForAccount(accountId, requestOptions );
         Assert.assertEquals(thirdInvoiceEmailJson.getAccountId(), accountId);
         Assert.assertFalse(thirdInvoiceEmailJson.isNotifiedForInvoices());
     }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
index 953b902..369bbf4 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
@@ -27,27 +27,23 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AccountTimeline;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.Credit;
-import org.killbill.billing.client.model.EventSubscription;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentTransaction;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AccountTimeline;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.Credit;
+import org.killbill.billing.client.model.gen.EventSubscription;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.audit.ChangeType;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.HashMultimap;
-
-import static org.killbill.billing.jaxrs.resources.JaxrsResource.QUERY_PARALLEL;
-
 public class TestAccountTimeline extends TestJaxrsBase {
 
     private static final String PAYMENT_REQUEST_PROCESSOR = "PaymentRequestProcessor";
@@ -69,11 +65,11 @@ public class TestAccountTimeline extends TestJaxrsBase {
 
         final List<EventSubscription> events = timeline.getBundles().get(0).getSubscriptions().get(0).getEvents();
         Assert.assertEquals(events.get(0).getEffectiveDate(), new LocalDate(2012, 4, 25));
-        Assert.assertEquals(events.get(0).getEventType(), "START_ENTITLEMENT");
+        Assert.assertEquals(events.get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT);
         Assert.assertEquals(events.get(1).getEffectiveDate(), new LocalDate(2012, 4, 25));
-        Assert.assertEquals(events.get(1).getEventType(), "START_BILLING");
+        Assert.assertEquals(events.get(1).getEventType(), SubscriptionEventType.START_BILLING);
         Assert.assertEquals(events.get(2).getEffectiveDate(), new LocalDate(2012, 5, 25));
-        Assert.assertEquals(events.get(2).getEventType(), "PHASE");
+        Assert.assertEquals(events.get(2).getEventType(), SubscriptionEventType.PHASE);
     }
 
     @Test(groups = "slow", description = "Can retrieve the timeline with audits")
@@ -83,27 +79,27 @@ public class TestAccountTimeline extends TestJaxrsBase {
         final DateTime endTime = clock.getUTCNow();
 
         // Add credit
-        final Invoice invoice = killBillClient.getInvoicesForAccount(accountJson.getAccountId()).get(1);
+        final Invoice invoice = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).get(1);
         final BigDecimal creditAmount = BigDecimal.ONE;
         final Credit credit = new Credit();
         credit.setAccountId(accountJson.getAccountId());
         credit.setCreditAmount(creditAmount);
-        killBillClient.createCredit(credit, true, createdBy, reason, comment);
+        creditApi.createCredit(credit, true, requestOptions);
 
         // Add refund
-        final Payment postedPayment = killBillClient.getPaymentsForAccount(accountJson.getAccountId()).get(0);
+        final Payment postedPayment = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions).get(0);
         final BigDecimal refundAmount = BigDecimal.ONE;
         final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
         refund.setPaymentId(postedPayment.getPaymentId());
         refund.setAmount(refundAmount);
-        killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+        invoicePaymentApi.createRefundWithAdjustments(postedPayment.getPaymentId(), refund, accountJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // Add chargeback
         final BigDecimal chargebackAmount = BigDecimal.ONE;
         final InvoicePaymentTransaction chargeback = new InvoicePaymentTransaction();
         chargeback.setPaymentId(postedPayment.getPaymentId());
         chargeback.setAmount(chargebackAmount);
-        killBillClient.createInvoicePaymentChargeback(chargeback, createdBy, reason, comment);
+        invoicePaymentApi.createChargeback(postedPayment.getPaymentId(), chargeback, requestOptions);
 
         // Verify payments
         verifyPayments(accountJson.getAccountId(), startTime, endTime, refundAmount, chargebackAmount);
@@ -127,18 +123,18 @@ public class TestAccountTimeline extends TestJaxrsBase {
             final InvoicePayment payment = timeline.getPayments().get(0);
 
             // Verify payments
-            final List<PaymentTransaction> purchaseTransactions = getPaymentTransactions(timeline.getPayments(), TransactionType.PURCHASE.toString());
+            final List<PaymentTransaction> purchaseTransactions = getInvoicePaymentTransactions(timeline.getPayments(), TransactionType.PURCHASE);
             Assert.assertEquals(purchaseTransactions.size(), 1);
             final PaymentTransaction purchaseTransaction = purchaseTransactions.get(0);
 
             // Verify refunds
-            final List<PaymentTransaction> refundTransactions = getPaymentTransactions(timeline.getPayments(), TransactionType.REFUND.toString());
+            final List<PaymentTransaction> refundTransactions = getInvoicePaymentTransactions(timeline.getPayments(), TransactionType.REFUND);
             Assert.assertEquals(refundTransactions.size(), 1);
             final PaymentTransaction refundTransaction = refundTransactions.get(0);
             Assert.assertEquals(refundTransaction.getPaymentId(), payment.getPaymentId());
             Assert.assertEquals(refundTransaction.getAmount().compareTo(refundAmount), 0);
 
-            final List<PaymentTransaction> chargebackTransactions = getPaymentTransactions(timeline.getPayments(), TransactionType.CHARGEBACK.toString());
+            final List<PaymentTransaction> chargebackTransactions = getInvoicePaymentTransactions(timeline.getPayments(), TransactionType.CHARGEBACK);
             Assert.assertEquals(chargebackTransactions.size(), 1);
             final PaymentTransaction chargebackTransaction = chargebackTransactions.get(0);
             Assert.assertEquals(chargebackTransaction.getPaymentId(), payment.getPaymentId());
@@ -308,13 +304,10 @@ public class TestAccountTimeline extends TestJaxrsBase {
     }
 
     private AccountTimeline getAccountTimeline(final UUID accountId, final AuditLevel auditLevel) throws KillBillClientException {
-        final AccountTimeline accountTimeline = killBillClient.getAccountTimeline(accountId, auditLevel, RequestOptions.empty());
+        final AccountTimeline accountTimeline = accountApi.getAccountTimeline(accountId, false, auditLevel, requestOptions);
 
         // Verify also the parallel path
-        final HashMultimap<String, String> queryParams = HashMultimap.<String, String>create();
-        queryParams.put(QUERY_PARALLEL, "true");
-        final RequestOptions requestOptions = RequestOptions.builder().withQueryParams(queryParams).build();
-        final AccountTimeline accountTimelineInParallel = killBillClient.getAccountTimeline(accountId, auditLevel, requestOptions);
+        final AccountTimeline accountTimelineInParallel = accountApi.getAccountTimeline(accountId, true, auditLevel, requestOptions);
         Assert.assertEquals(accountTimelineInParallel, accountTimeline);
 
         return accountTimeline;
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAdmin.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAdmin.java
index 56e1427..9ecd021 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAdmin.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAdmin.java
@@ -25,20 +25,19 @@ import java.util.Map;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.api.FlakyRetryAnalyzer;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.JaxrsResource;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.KillBillHttpClient;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentTransaction;
-import org.killbill.billing.jaxrs.json.AdminPaymentJson;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AdminPayment;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.payment.api.TransactionStatus;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.jackson.ObjectMapper;
 import org.testng.Assert;
@@ -47,9 +46,7 @@ import org.testng.annotations.Test;
 import com.ning.http.client.Response;
 
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -69,17 +66,17 @@ public class TestAdmin extends TestJaxrsBase {
         authTransaction.setCurrency(account.getCurrency());
         authTransaction.setPaymentExternalKey(paymentExternalKey);
         authTransaction.setTransactionExternalKey(authTransactionExternalKey);
-        authTransaction.setTransactionType("AUTHORIZE");
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
         callbackServlet.pushExpectedEvent(ExtBusEventType.PAYMENT_SUCCESS);
-        final Payment authPayment = killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction, requestOptions);
+        final Payment authPayment = accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(), NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
 
         fixPaymentState(authPayment, "AUTH_FAILED", "AUTH_FAILED", TransactionStatus.PAYMENT_FAILURE);
 
-        final Payment updatedPayment = killBillClient.getPayment(authPayment.getPaymentId());
+        final Payment updatedPayment = paymentApi.getPayment(authPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(updatedPayment.getTransactions().size(), 1);
         final PaymentTransaction authTransaction2 = updatedPayment.getTransactions().get(0);
-        Assert.assertEquals(authTransaction2.getStatus(), TransactionStatus.PAYMENT_FAILURE.toString());
+        Assert.assertEquals(authTransaction2.getStatus(), TransactionStatus.PAYMENT_FAILURE);
 
         // Capture should fail because lastSuccessPaymentState was moved to AUTH_FAILED
         doCapture(updatedPayment, true);
@@ -96,16 +93,16 @@ public class TestAdmin extends TestJaxrsBase {
             assertNotNull(accountJson);
             accounts.add(accountJson.getAccountId());
 
-            createEntitlement(accountJson.getAccountId(),
-                              UUID.randomUUID().toString(),
-                              "Shotgun",
-                              ProductCategory.BASE,
-                              BillingPeriod.MONTHLY,
-                              true);
+            createSubscription(accountJson.getAccountId(),
+                               UUID.randomUUID().toString(),
+                               "Shotgun",
+                               ProductCategory.BASE,
+                               BillingPeriod.MONTHLY,
+                               true);
             clock.addDays(2);
 
-            Assert.assertEquals(killBillClient.getInvoices(requestOptions).getPaginationMaxNbRecords(), i + 1);
-            final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), false, false, false, false, AuditLevel.NONE, requestOptions);
+            Assert.assertEquals(invoiceApi.getInvoices(requestOptions).getPaginationMaxNbRecords(), i + 1);
+            final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), false, false, false, false, AuditLevel.NONE, requestOptions);
             assertEquals(invoices.size(), 1);
         }
 
@@ -116,9 +113,9 @@ public class TestAdmin extends TestJaxrsBase {
         clock.addDays(32);
         callbackServlet.assertListenerStatus();
 
-        Assert.assertEquals(killBillClient.getInvoices(requestOptions).getPaginationMaxNbRecords(), 10);
+        Assert.assertEquals(invoiceApi.getInvoices(requestOptions).getPaginationMaxNbRecords(), 10);
         for (final UUID accountId : accounts) {
-            final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountId, false, false, false, false, AuditLevel.NONE, requestOptions);
+            final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountId, false, false, false, false, AuditLevel.NONE, requestOptions);
             assertEquals(invoices.size(), 2);
         }
 
@@ -128,7 +125,7 @@ public class TestAdmin extends TestJaxrsBase {
         perTenantProperties.put("org.killbill.invoice.enabled", "false");
         final String perTenantConfig = mapper.writeValueAsString(perTenantProperties);
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        killBillClient.postConfigurationPropertiesForTenant(perTenantConfig, requestOptions);
+        tenantApi.uploadPerTenantConfiguration(perTenantConfig, requestOptions);
         callbackServlet.assertListenerStatus();
 
         // Verify the second invoice isn't generated
@@ -138,26 +135,26 @@ public class TestAdmin extends TestJaxrsBase {
         clock.addDays(32);
         callbackServlet.assertListenerStatus();
 
-        Assert.assertEquals(killBillClient.getInvoices(requestOptions).getPaginationMaxNbRecords(), 10);
+        Assert.assertEquals(invoiceApi.getInvoices(requestOptions).getPaginationMaxNbRecords(), 10);
         for (final UUID accountId : accounts) {
-            final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountId, false, false, false, false, AuditLevel.NONE, requestOptions);
+            final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountId, false, false, false, false, AuditLevel.NONE, requestOptions);
             assertEquals(invoices.size(), 2);
         }
 
         // Fix one account
         final Response response = triggerInvoiceGenerationForParkedAccounts(1);
         Assert.assertEquals(response.getResponseBody(), "{\"" + accounts.get(0) + "\":\"OK\"}");
-        Assert.assertEquals(killBillClient.getInvoices(requestOptions).getPaginationMaxNbRecords(), 11);
+        Assert.assertEquals(invoiceApi.getInvoices(requestOptions).getPaginationMaxNbRecords(), 11);
 
         // Fix all accounts
         final Response response2 = triggerInvoiceGenerationForParkedAccounts(4);
-        final Map<String,String> fixedAccounts = mapper.readValue(response2.getResponseBody(), new TypeReference<Map<String,String>>() {});
+        final Map<String, String> fixedAccounts = mapper.readValue(response2.getResponseBody(), new TypeReference<Map<String, String>>() {});
         Assert.assertEquals(fixedAccounts.size(), 4);
         Assert.assertEquals(fixedAccounts.get(accounts.get(1).toString()), "OK");
         Assert.assertEquals(fixedAccounts.get(accounts.get(2).toString()), "OK");
         Assert.assertEquals(fixedAccounts.get(accounts.get(3).toString()), "OK");
         Assert.assertEquals(fixedAccounts.get(accounts.get(4).toString()), "OK");
-        Assert.assertEquals(killBillClient.getInvoices(requestOptions).getPaginationMaxNbRecords(), 15);
+        Assert.assertEquals(invoiceApi.getInvoices(requestOptions).getPaginationMaxNbRecords(), 15);
     }
 
     private void doCapture(final Payment payment, final boolean expectException) throws KillBillClientException {
@@ -171,7 +168,7 @@ public class TestAdmin extends TestJaxrsBase {
         captureTransaction.setPaymentExternalKey(payment.getPaymentExternalKey());
         captureTransaction.setTransactionExternalKey(capture1TransactionExternalKey);
         try {
-            killBillClient.captureAuthorization(captureTransaction, requestOptions);
+            paymentApi.captureAuthorization(payment.getPaymentId(), captureTransaction, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
             if (expectException) {
                 Assert.fail("Capture should not succeed, after auth was moved to a PAYMENT_FAILURE");
             }
@@ -184,19 +181,9 @@ public class TestAdmin extends TestJaxrsBase {
     }
 
     private void fixPaymentState(final Payment payment, final String lastSuccessPaymentState, final String currentPaymentStateName, final TransactionStatus transactionStatus) throws KillBillClientException {
-        //
-        // We do not expose the endpoint in the client API on purpose since this should only be accessed using special permission ADMIN_CAN_FIX_DATA
-        // for when there is a need to fix payment state.
-        //
-        final String uri = "/1.0/kb/admin/payments/" + payment.getPaymentId().toString() + "/transactions/" + payment.getTransactions().get(0).getTransactionId().toString();
-
-        final AdminPaymentJson body = new AdminPaymentJson(lastSuccessPaymentState, currentPaymentStateName, transactionStatus.toString());
-        final Multimap result = HashMultimap.create();
-        result.put(KillBillHttpClient.AUDIT_OPTION_CREATED_BY, createdBy);
-        result.put(KillBillHttpClient.AUDIT_OPTION_REASON, reason);
-        result.put(KillBillHttpClient.AUDIT_OPTION_COMMENT, comment);
         callbackServlet.pushExpectedEvent(ExtBusEventType.PAYMENT_FAILED);
-        killBillHttpClient.doPut(uri, body, result);
+        final AdminPayment body = new AdminPayment(lastSuccessPaymentState, currentPaymentStateName, transactionStatus.toString());
+        adminApi.updatePaymentTransactionState(payment.getPaymentId(), payment.getTransactions().get(0).getTransactionId(), body, requestOptions);
         callbackServlet.assertListenerStatus();
     }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
index 4323f25..6159986 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
@@ -25,12 +25,12 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.BlockingState;
 import org.killbill.billing.client.model.BlockingStates;
-import org.killbill.billing.client.model.Bundle;
 import org.killbill.billing.client.model.Bundles;
-import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.BlockingState;
+import org.killbill.billing.client.model.gen.Bundle;
+import org.killbill.billing.client.model.gen.Subscription;
 import org.killbill.billing.entitlement.api.BlockingStateType;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.util.api.AuditLevel;
@@ -50,9 +50,10 @@ public class TestBundle extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Can create bundles without an external key")
     public void testCreateBundleWithNoExternalKey() throws Exception {
-        final Account accountJson = createAccount();
+        final Account accountJson;
+        accountJson = createAccount();
 
-        final Subscription subscription = createEntitlement(accountJson.getAccountId(), null, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        final Subscription subscription = createSubscription(accountJson.getAccountId(), null, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         Assert.assertNotNull(subscription.getExternalKey());
     }
 
@@ -60,20 +61,20 @@ public class TestBundle extends TestJaxrsBase {
     public void testBundleOk() throws Exception {
         final Account accountJson = createAccount();
 
-        createEntitlement(accountJson.getAccountId(), "123467", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(accountJson.getAccountId(), "123467", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
         // Retrieves by external key
-        final List<Bundle> objFromJson = killBillClient.getAccountBundles(accountJson.getAccountId(), "123467");
+        final List<Bundle> objFromJson = accountApi.getAccountBundles(accountJson.getAccountId(), "123467", null, requestOptions);
         Assert.assertEquals(objFromJson.size(), 1);
     }
 
     @Test(groups = "slow", description = "Can retrieve account bundles")
     public void testBundleFromAccount() throws Exception {
         final Account accountJson = createAccount();
-        createEntitlement(accountJson.getAccountId(), "156567", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
-        createEntitlement(accountJson.getAccountId(), "265658", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(accountJson.getAccountId(), "156567", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(accountJson.getAccountId(), "265658", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
-        final List<Bundle> objFromJson = killBillClient.getAccountBundles(accountJson.getAccountId());
+        final List<Bundle> objFromJson = accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions);
         Assert.assertEquals(objFromJson.size(), 2);
     }
 
@@ -82,21 +83,22 @@ public class TestBundle extends TestJaxrsBase {
         final Account accountJson = createAccount();
 
         // ID
-        Assert.assertNull(killBillClient.getBundle(UUID.randomUUID(), requestOptions));
+        Assert.assertNull(bundleApi.getBundle(UUID.randomUUID(), requestOptions));
 
         // External Key
-        Assert.assertNull(killBillClient.getBundle(UUID.randomUUID().toString(), requestOptions));
-        Assert.assertTrue(killBillClient.getAllBundlesForExternalKey(UUID.randomUUID().toString(), requestOptions).isEmpty());
+        Assert.assertTrue(bundleApi.getBundleByKey(UUID.randomUUID().toString(), requestOptions).isEmpty());
+        
+        Assert.assertTrue(bundleApi.getBundleByKey(UUID.randomUUID().toString(), requestOptions).isEmpty());
 
         // Account Id
-        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), "98374982743892", requestOptions).isEmpty());
-        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions).isEmpty());
+        Assert.assertTrue(accountApi.getAccountBundles(accountJson.getAccountId(), "98374982743892", null, requestOptions).isEmpty());
+        Assert.assertTrue(accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions).isEmpty());
 
     }
 
     @Test(groups = "slow", description = "Can handle non existent account")
     public void testAccountNonExistent() throws Exception {
-        Assert.assertTrue(killBillClient.getAccountBundles(UUID.randomUUID()).isEmpty());
+        Assert.assertTrue(accountApi.getAccountBundles(UUID.randomUUID(), null, null, requestOptions).isEmpty());
     }
 
     @Test(groups = "slow", description = "Can transfer bundle")
@@ -110,10 +112,16 @@ public class TestBundle extends TestJaxrsBase {
         final BillingPeriod term = BillingPeriod.MONTHLY;
         final String bundleExternalKey = "93199";
 
-        final Subscription entitlementJsonNoEvents = createEntitlement(accountJson.getAccountId(), bundleExternalKey, productName,
+        final Subscription entitlementJsonNoEvents = createSubscription(accountJson.getAccountId(), bundleExternalKey, productName,
                                                                        ProductCategory.BASE, term, true);
 
-        final Bundle originalBundle = killBillClient.getBundle(bundleExternalKey, requestOptions);
+        Bundles existingBundles = bundleApi.getBundleByKey(bundleExternalKey, requestOptions);
+        assertEquals(existingBundles.size(), 1);
+        Bundle originalBundle = existingBundles.get(0);
+        existingBundles = bundleApi.getBundleByKey(bundleExternalKey, requestOptions);
+        assertEquals(existingBundles.size(), 1);
+        originalBundle = existingBundles.get(0);
+        assertEquals(originalBundle.getAccountId(), accountJson.getAccountId());
         assertEquals(originalBundle.getAccountId(), accountJson.getAccountId());
         assertEquals(originalBundle.getExternalKey(), bundleExternalKey);
 
@@ -122,15 +130,16 @@ public class TestBundle extends TestJaxrsBase {
         final Bundle bundle = new Bundle();
         bundle.setAccountId(newAccount.getAccountId());
         bundle.setBundleId(entitlementJsonNoEvents.getBundleId());
-        assertEquals(killBillClient.transferBundle(bundle, createdBy, reason, comment).getAccountId(), newAccount.getAccountId());
+        bundleApi.transferBundle(entitlementJsonNoEvents.getBundleId(), bundle, null, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final Bundle newBundle = killBillClient.getBundle(bundleExternalKey, requestOptions);
+        existingBundles = bundleApi.getBundleByKey(bundleExternalKey, requestOptions);
+        assertEquals(existingBundles.size(), 1);
+        final Bundle newBundle = existingBundles.get(0);
         assertNotEquals(newBundle.getBundleId(), originalBundle.getBundleId());
         assertEquals(newBundle.getExternalKey(), originalBundle.getExternalKey());
         assertEquals(newBundle.getAccountId(), newAccount.getAccountId());
 
-
-        final Bundles bundles = killBillClient.getAllBundlesForExternalKey(bundleExternalKey, requestOptions);
+        final Bundles bundles = bundleApi.getBundleByKey(bundleExternalKey, true, AuditLevel.NONE, requestOptions);
         assertEquals(bundles.size(), 2);
         assertSubscriptionState(bundles, originalBundle.getBundleId(), EntitlementState.CANCELLED);
         assertSubscriptionState(bundles, newBundle.getBundleId(), EntitlementState.ACTIVE);
@@ -159,34 +168,36 @@ public class TestBundle extends TestJaxrsBase {
         final BillingPeriod term = BillingPeriod.MONTHLY;
         final String bundleExternalKey = "93199";
 
-        final Subscription entitlement = createEntitlement(accountJson.getAccountId(), bundleExternalKey, productName,
+        final Subscription entitlement = createSubscription(accountJson.getAccountId(), bundleExternalKey, productName,
                                                            ProductCategory.BASE, term, true);
 
-        final Bundle bundle = killBillClient.getBundle(bundleExternalKey);
+        Bundles existingBundles = bundleApi.getBundleByKey(bundleExternalKey, requestOptions);
+        assertEquals(existingBundles.size(), 1);
+        final Bundle bundle = existingBundles.get(0);
         assertEquals(bundle.getAccountId(), accountJson.getAccountId());
         assertEquals(bundle.getExternalKey(), bundleExternalKey);
 
         final BlockingState blockingState = new BlockingState(bundle.getBundleId(), "block", "service", false, true, true, null, BlockingStateType.SUBSCRIPTION_BUNDLE, null);
-        killBillClient.setBlockingState(bundle.getBundleId(), blockingState, clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), ImmutableMap.<String, String>of(), createdBy, reason, comment);
+        bundleApi.addBundleBlockingState(bundle.getBundleId(), blockingState, clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), ImmutableMap.<String, String>of(), requestOptions);
 
-        final Subscription subscription = killBillClient.getSubscription(entitlement.getSubscriptionId());
+        final Subscription subscription = subscriptionApi.getSubscription(entitlement.getSubscriptionId(), requestOptions);
         assertEquals(subscription.getState(), EntitlementState.BLOCKED);
 
         clock.addDays(1);
 
         final BlockingState unblockingState = new BlockingState(bundle.getBundleId(), "unblock", "service", false, false, false, null, BlockingStateType.SUBSCRIPTION_BUNDLE, null);
-        killBillClient.setBlockingState(bundle.getBundleId(), unblockingState, clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), ImmutableMap.<String, String>of(), createdBy, reason, comment);
+        bundleApi.addBundleBlockingState(bundle.getBundleId(), unblockingState, clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), ImmutableMap.<String, String>of(), requestOptions);
 
-        final Subscription subscription2 = killBillClient.getSubscription(entitlement.getSubscriptionId());
+        final Subscription subscription2 = subscriptionApi.getSubscription(entitlement.getSubscriptionId(), requestOptions);
         assertEquals(subscription2.getState(), EntitlementState.ACTIVE);
 
-        final BlockingStates blockingStates = killBillClient.getBlockingStates(accountJson.getAccountId(), null, ImmutableList.<String>of("service"), AuditLevel.FULL, requestOptions);
+        final BlockingStates blockingStates = accountApi.getBlockingStates(accountJson.getAccountId(), null, ImmutableList.<String>of("service"), AuditLevel.FULL, requestOptions);
         Assert.assertEquals(blockingStates.size(), 2);
 
-        final BlockingStates blockingStates2 = killBillClient.getBlockingStates(accountJson.getAccountId(), ImmutableList.<BlockingStateType>of(BlockingStateType.SUBSCRIPTION_BUNDLE), null, AuditLevel.FULL, requestOptions);
+        final BlockingStates blockingStates2 = accountApi.getBlockingStates(accountJson.getAccountId(), ImmutableList.<BlockingStateType>of(BlockingStateType.SUBSCRIPTION_BUNDLE), null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(blockingStates2.size(), 2);
 
-        final BlockingStates blockingStates3 = killBillClient.getBlockingStates(accountJson.getAccountId(), null, null, AuditLevel.FULL, requestOptions);
+        final BlockingStates blockingStates3 = accountApi.getBlockingStates(accountJson.getAccountId(), null, null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(blockingStates3.size(), 3);
     }
 
@@ -195,19 +206,19 @@ public class TestBundle extends TestJaxrsBase {
         final Account accountJson = createAccount();
 
         for (int i = 0; i < 5; i++) {
-            createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+            createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         }
 
-        final Bundles allBundles = killBillClient.getBundles();
+        final Bundles allBundles = bundleApi.getBundles(requestOptions);
         Assert.assertEquals(allBundles.size(), 5);
 
         for (final Bundle bundle : allBundles) {
-            Assert.assertEquals(killBillClient.searchBundles(bundle.getBundleId().toString()).size(), 1);
-            Assert.assertEquals(killBillClient.searchBundles(bundle.getAccountId().toString()).size(), 5);
-            Assert.assertEquals(killBillClient.searchBundles(bundle.getExternalKey()).size(), 1);
+            Assert.assertEquals(bundleApi.searchBundles(bundle.getBundleId().toString(), requestOptions).size(), 1);
+            Assert.assertEquals(bundleApi.searchBundles(bundle.getAccountId().toString(), requestOptions).size(), 5);
+            Assert.assertEquals(bundleApi.searchBundles(bundle.getExternalKey(), requestOptions).size(), 1);
         }
 
-        Bundles page = killBillClient.getBundles(0L, 1L);
+        Bundles page = bundleApi.getBundles(0L, 1L, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java
index 83b74fe..4adf0a7 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java
@@ -17,13 +17,15 @@
 
 package org.killbill.billing.jaxrs;
 
+import java.io.File;
+import java.nio.charset.Charset;
 import java.util.UUID;
 
 import org.killbill.automaton.StateMachineConfig;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.catalog.api.Catalog;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Tenant;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Tenant;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.overdue.api.OverdueConfig;
 import org.killbill.billing.util.cache.Cachable.CacheType;
@@ -32,6 +34,7 @@ import org.killbill.billing.util.config.tenant.PerTenantConfig;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.io.Files;
 import com.google.common.io.Resources;
 
 import static org.testng.Assert.assertFalse;
@@ -49,7 +52,7 @@ public class TestCache extends TestJaxrsBase {
         Assert.assertEquals(cache.size(), 1);
 
         // invalidate the specified cache
-        killBillClient.invalidateCacheByName(CacheType.RECORD_ID.getCacheName(), requestOptions);
+        adminApi.invalidatesCache(CacheType.RECORD_ID.getCacheName(), requestOptions);
 
         // verify that now the cache is empty and has no keys stored
         Assert.assertEquals(cache.size(), 0);
@@ -64,7 +67,7 @@ public class TestCache extends TestJaxrsBase {
         Assert.assertEquals(cache.size(), 1);
 
         // invalidate all caches
-        killBillClient.invalidateAllCaches(requestOptions);
+        adminApi.invalidatesCache(null, requestOptions);
 
         // verify that now the cache is empty and has no keys stored
         Assert.assertEquals(cache.size(), 0);
@@ -86,7 +89,7 @@ public class TestCache extends TestJaxrsBase {
         assertTrue(accountBcdCache.isKeyInCache(input.getAccountId()));
 
         // invalidate caches per account level by accountId
-        killBillClient.invalidateCacheByAccount(input.getAccountId().toString(), requestOptions);
+        adminApi.invalidatesCacheByAccount(input.getAccountId(), requestOptions);
 
         // verify that now the caches don't have the accountId key stored
         Assert.assertFalse(accountRecordIdCache.isKeyInCache(input.getAccountId().toString()));
@@ -101,7 +104,10 @@ public class TestCache extends TestJaxrsBase {
 
         // Uploading the test catalog using the new Tenant created before
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        killBillClient.uploadXMLCatalog(Resources.getResource("SpyCarAdvanced.xml").getPath(), requestOptions);
+        final String catalogPath = Resources.getResource("SpyCarAdvanced.xml").getPath();
+        final File catalogFile = new File(catalogPath);
+        final String body = Files.toString(catalogFile, Charset.forName("UTF-8"));
+        catalogApi.uploadCatalogXml(body, requestOptions);
         callbackServlet.assertListenerStatus();
 
         // creating an Account with PaymentMethod and a Subscription
@@ -128,7 +134,7 @@ public class TestCache extends TestJaxrsBase {
         assertTrue(tenantCatalogCache.isKeyInCache(tenantRecordId));
 
         // invalidate caches per tenant level
-        killBillClient.invalidateCacheByTenant(requestOptions);
+        adminApi.invalidatesCache(null, requestOptions);
 
         // verify that now the caches don't have the previous values
         assertFalse(tenantRecordIdCache.isKeyInCache(currentTenant.getTenantId().toString()));
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index cbb6486..7ca4f03 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -19,37 +19,37 @@
 package org.killbill.billing.jaxrs;
 
 import java.math.BigDecimal;
-import java.sql.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.catalog.api.TimeUnit;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Catalog;
-import org.killbill.billing.client.model.Plan;
-import org.killbill.billing.client.model.PlanDetail;
-import org.killbill.billing.client.model.Product;
-import org.killbill.billing.client.model.SimplePlan;
-import org.killbill.billing.client.model.Usage;
+import org.killbill.billing.client.model.Catalogs;
+import org.killbill.billing.client.model.gen.Catalog;
+import org.killbill.billing.client.model.gen.Plan;
+import org.killbill.billing.client.model.gen.PlanDetail;
+import org.killbill.billing.client.model.gen.Product;
+import org.killbill.billing.client.model.gen.SimplePlan;
+import org.killbill.billing.client.model.gen.Usage;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.io.Resources;
 
 public class TestCatalog extends TestJaxrsBase {
 
+
     @Test(groups = "slow", description = "Upload and retrieve a per tenant catalog")
     public void testMultiTenantCatalog() throws Exception {
-        final String versionPath1 = Resources.getResource("SpyCarBasic.xml").getPath();
-        killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
-        String catalog = killBillClient.getXMLCatalog(requestOptions);
+        String catalog = uploadTenantCatalog("SpyCarBasic.xml", true);
         Assert.assertNotNull(catalog);
         //
         // We can't deserialize the VersionedCatalog using our JAXB models because it contains several
@@ -59,21 +59,17 @@ public class TestCatalog extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testUploadAndFetchUsageCatlog() throws Exception {
-        final String versionPath1 = Resources.getResource("UsageExperimental.xml").getPath();
-        killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
-        String catalog = killBillClient.getXMLCatalog(requestOptions);
+        String catalog = uploadTenantCatalog("UsageExperimental.xml", true);
         Assert.assertNotNull(catalog);
     }
 
-
     @Test(groups = "slow")
     public void testUploadWithErrors() throws Exception {
-        final String versionPath1 = Resources.getResource("SpyCarBasic.xml").getPath();
-        killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
+        uploadTenantCatalog("SpyCarBasic.xml", false);
 
         // Retry to upload same version
         try {
-            killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
+            uploadTenantCatalog("SpyCarBasic.xml", false);
             Assert.fail("Uploading same version should fail");
         } catch (KillBillClientException e) {
             Assert.assertTrue(e.getMessage().startsWith("Invalid catalog for tenant : "));
@@ -81,14 +77,13 @@ public class TestCatalog extends TestJaxrsBase {
 
         // Try to upload another version with an invalid name (different than orignal name)
         try {
-            final String versionPath2 = Resources.getResource("SpyCarBasicInvalidName.xml").getPath();
-            killBillClient.uploadXMLCatalog(versionPath2, requestOptions);
+            uploadTenantCatalog("SpyCarBasicInvalidName.xml", false);
             Assert.fail("Uploading same version should fail");
         } catch (KillBillClientException e) {
             Assert.assertTrue(e.getMessage().startsWith("Invalid catalog for tenant : "));
         }
 
-        String catalog = killBillClient.getXMLCatalog(requestOptions);
+        String catalog = catalogApi.getCatalogXml(null, null, requestOptions);
         Assert.assertNotNull(catalog);
     }
 
@@ -96,10 +91,10 @@ public class TestCatalog extends TestJaxrsBase {
     public void testCatalog() throws Exception {
         final Set<String> allBasePlans = new HashSet<String>();
 
-        final List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        final Catalogs catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
 
         Assert.assertEquals(catalogsJson.get(0).getName(), "Firearms");
-        Assert.assertEquals(catalogsJson.get(0).getEffectiveDate(), Date.valueOf("2011-01-01"));
+        Assert.assertEquals(catalogsJson.get(0).getEffectiveDate().toLocalDate(), new LocalDate("2011-01-01"));
         Assert.assertEquals(catalogsJson.get(0).getCurrencies().size(), 3);
         Assert.assertEquals(catalogsJson.get(0).getProducts().size(), 13);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(), 7);
@@ -129,7 +124,7 @@ public class TestCatalog extends TestJaxrsBase {
             }
 
             // Retrieve available products (addons) for that base product
-            final List<PlanDetail> availableAddons = killBillClient.getAvailableAddons(productJson.getName(), requestOptions);
+            final List<PlanDetail> availableAddons = catalogApi.getAvailableAddons(productJson.getName(), null, null, requestOptions);
             final Set<String> availableAddonsNames = new HashSet<String>();
             for (final PlanDetail planDetailJson : availableAddons) {
                 availableAddonsNames.add(planDetailJson.getProduct());
@@ -138,7 +133,7 @@ public class TestCatalog extends TestJaxrsBase {
         }
 
         // Verify base plans endpoint
-        final List<PlanDetail> basePlans = killBillClient.getBasePlans(requestOptions);
+        final List<PlanDetail> basePlans = catalogApi.getAvailableBasePlans(null, requestOptions);
         final Set<String> foundBasePlans = new HashSet<String>();
         for (final PlanDetail planDetailJson : basePlans) {
             foundBasePlans.add(planDetailJson.getPlan());
@@ -148,7 +143,7 @@ public class TestCatalog extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Try to retrieve catalog with an effective date in the past")
     public void testCatalogWithEffectiveDateInThePast() throws Exception {
-        final List<Catalog> catalogsJson = killBillClient.getJSONCatalog(DateTime.parse("2008-01-01"), requestOptions);
+        final List<Catalog> catalogsJson = catalogApi.getCatalogJson(DateTime.parse("2008-01-01"), null, requestOptions);
         // We expect to see our catalogTest.xml (date in the past returns the first version. See #760
         Assert.assertEquals(catalogsJson.size(), 1);
     }
@@ -156,24 +151,23 @@ public class TestCatalog extends TestJaxrsBase {
     @Test(groups = "slow", description = "Can create a simple Plan into a per-tenant catalog")
     public void testAddSimplePlan() throws Exception {
 
-        killBillClient.addSimplePan(new SimplePlan("foo-monthly", "Foo", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
-        List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptions);
-        Assert.assertEquals(catalogsJson.size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
-        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+        catalogApi.addSimplePlan(new SimplePlan("foo-monthly", "Foo", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
+        List<Catalog> catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(), "Foo");
+        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().get(0), "foo-monthly");
 
+        catalogApi.addSimplePlan(new SimplePlan("foo-annual", "Foo", ProductCategory.BASE, Currency.USD, new BigDecimal("100.00"), BillingPeriod.ANNUAL, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
 
-        killBillClient.addSimplePan(new SimplePlan("foo-annual", "Foo", ProductCategory.BASE, Currency.USD, new BigDecimal("100.00"), BillingPeriod.ANNUAL, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
-
-        catalogsJson = killBillClient.getJSONCatalog(requestOptions);
-        Assert.assertEquals(catalogsJson.size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
-        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+        catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(), "Foo");
+        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 2);
 
@@ -185,27 +179,26 @@ public class TestCatalog extends TestJaxrsBase {
         createTenant(UUID.randomUUID().toString(), UUID.randomUUID().toString(), false);
 
         // Verify the template catalog is not returned
-        List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        List<Catalog> catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
         Assert.assertEquals(catalogsJson.size(), 0);
 
-        killBillClient.addSimplePan(new SimplePlan("foo-monthly", "Foo", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
-        catalogsJson = killBillClient.getJSONCatalog(requestOptions);
-        Assert.assertEquals(catalogsJson.size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
-        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+        catalogApi.addSimplePlan(new SimplePlan("foo-monthly", "Foo", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
+        catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(), "Foo");
+        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().get(0), "foo-monthly");
 
+        catalogApi.addSimplePlan(new SimplePlan("foo-annual", "Foo", ProductCategory.BASE, Currency.USD, new BigDecimal("100.00"), BillingPeriod.ANNUAL, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
 
-        killBillClient.addSimplePan(new SimplePlan("foo-annual", "Foo", ProductCategory.BASE, Currency.USD, new BigDecimal("100.00"), BillingPeriod.ANNUAL, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
-
-        catalogsJson = killBillClient.getJSONCatalog(requestOptions);
-        Assert.assertEquals(catalogsJson.size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
-        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
-        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+        catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().size(), 1);
+        Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(), "Foo");
+        Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(), 1);
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 2);
     }
@@ -213,24 +206,22 @@ public class TestCatalog extends TestJaxrsBase {
     @Test(groups = "slow")
     public void testCatalogDeletionInTestMode() throws Exception {
 
-        killBillClient.addSimplePan(new SimplePlan("something-monthly", "Something", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
-        List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        catalogApi.addSimplePlan(new SimplePlan("something-monthly", "Something", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
+        List<Catalog> catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
         Assert.assertEquals(catalogsJson.size(), 1);
 
-        killBillClient.deleteCatalog(requestOptions);
+        catalogApi.deleteCatalog(requestOptions);
 
         // Verify that we see no catalog -- and in particular not the KB default catalog
-        catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        catalogsJson = catalogApi.getCatalogJson(null, null, requestOptions);
         Assert.assertEquals(catalogsJson.size(), 0);
 
     }
 
     @Test(groups = "slow")
     public  void testGetCatalogVersions() throws Exception {
-        final String versionPath1 = Resources.getResource("SpyCarBasic.xml").getPath();
-        killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
-
-        List<DateTime> versions = killBillClient.getCatalogVersions(requestOptions);
+        uploadTenantCatalog("SpyCarBasic.xml", false);
+        List<DateTime> versions = catalogApi.getCatalogVersions(null, requestOptions);
         Assert.assertEquals(1, versions.size());
         Assert.assertEquals(versions.get(0).compareTo(DateTime.parse("2013-02-08T00:00:00+00:00")), 0);
     }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
index 58005dd..2559a84 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
@@ -25,15 +25,15 @@ import java.util.UUID;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
 import org.killbill.billing.client.model.InvoicePayments;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentTransaction;
-import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.Subscription;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
+import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -50,13 +50,13 @@ public class TestChargeback extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Can create a chargeback")
     public void testAddChargeback() throws Exception {
-        final Payment payment = createAccountWithInvoiceAndPayment();
+        final InvoicePayment payment = createAccountWithInvoiceAndPayment();
         createAndVerifyChargeback(payment);
     }
 
     @Test(groups = "slow", description = "Can create multiple chargebacks")
     public void testMultipleChargeback() throws Exception {
-        final Payment payment = createAccountWithInvoiceAndPayment();
+        final InvoicePayment payment = createAccountWithInvoiceAndPayment();
 
         // We get a 249.95 payment so we do 4 chargeback and then the fifth should fail
         final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
@@ -64,22 +64,22 @@ public class TestChargeback extends TestJaxrsBase {
         input.setAmount(new BigDecimal("50.00"));
         int count = 4;
         while (count-- > 0) {
-            assertNotNull(killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment));
+            assertNotNull(invoicePaymentApi.createChargeback(payment.getPaymentId(), input, requestOptions));
         }
 
         // Last attempt should fail because this is more than the Payment
-        final InvoicePayment foo = killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
-        final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(payment.getAccountId());
-        final List<PaymentTransaction> transactions = getPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+        final InvoicePayment foo = invoicePaymentApi.createChargeback(payment.getPaymentId(), input, requestOptions);
+        final InvoicePayments payments = accountApi.getInvoicePayments(payment.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final List<PaymentTransaction> transactions = getInvoicePaymentTransactions(payments, TransactionType.CHARGEBACK);
         Assert.assertEquals(transactions.size(), 5);
         int found = 0;
         for (final PaymentTransaction transaction : transactions) {
-            if (transaction.getStatus().equals("SUCCESS")) {
+            if (transaction.getStatus().equals(TransactionStatus.SUCCESS)) {
                 assertTrue(transaction.getAmount().compareTo(input.getAmount()) == 0);
                 assertEquals(transaction.getPaymentId(), input.getPaymentId());
                 found++;
             } else {
-                assertEquals(transaction.getStatus(), "PAYMENT_FAILURE");
+                assertEquals(transaction.getStatus(), TransactionStatus.PAYMENT_FAILURE);
                 found++;
             }
         }
@@ -88,17 +88,17 @@ public class TestChargeback extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Can add a chargeback for deleted payment methods")
     public void testAddChargebackForDeletedPaymentMethod() throws Exception {
-        final Payment payment = createAccountWithInvoiceAndPayment();
+        final InvoicePayment payment = createAccountWithInvoiceAndPayment();
 
         // Check the payment method exists
-        assertEquals(killBillClient.getAccount(payment.getAccountId()).getPaymentMethodId(), payment.getPaymentMethodId());
-        assertEquals(killBillClient.getPaymentMethod(payment.getPaymentMethodId()).getAccountId(), payment.getAccountId());
+        assertEquals(accountApi.getAccount(payment.getAccountId(), requestOptions).getPaymentMethodId(), payment.getPaymentMethodId());
+        assertEquals(paymentMethodApi.getPaymentMethod(payment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions).getAccountId(), payment.getAccountId());
 
         // Delete the payment method
-        killBillClient.deletePaymentMethod(payment.getPaymentMethodId(), true, false, createdBy, reason, comment);
+        paymentMethodApi.deletePaymentMethod(payment.getPaymentMethodId(), true, false, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // Check the payment method was deleted
-        assertNull(killBillClient.getAccount(payment.getAccountId()).getPaymentMethodId());
+        assertNull(accountApi.getAccount(payment.getAccountId(), requestOptions).getPaymentMethodId());
 
         createAndVerifyChargeback(payment);
     }
@@ -110,7 +110,7 @@ public class TestChargeback extends TestJaxrsBase {
         input.setPaymentId(input.getPaymentId());
         input.setAmount(BigDecimal.TEN);
         try {
-            killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
+            invoicePaymentApi.createChargeback(input.getPaymentId(), input, requestOptions);
             fail();
         } catch (NullPointerException e) {
         } catch (KillBillClientException e) {
@@ -120,13 +120,13 @@ public class TestChargeback extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Cannot add a badly formatted chargeback")
     public void testBadRequest() throws Exception {
-        final Payment payment = createAccountWithInvoiceAndPayment();
+        final InvoicePayment payment = createAccountWithInvoiceAndPayment();
 
         final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
         input.setPaymentId(payment.getPaymentId());
 
         try {
-            killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
+            invoicePaymentApi.createChargeback(payment.getPaymentId(), input, requestOptions);
             fail();
         } catch (final KillBillClientException e) {
         }
@@ -134,33 +134,33 @@ public class TestChargeback extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Accounts can have zero chargeback")
     public void testNoChargebackForAccount() throws Exception {
-        final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(UUID.randomUUID());
-        final List<PaymentTransaction> transactions = getPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+        final List<InvoicePayment> payments = accountApi.getInvoicePayments(UUID.randomUUID(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final List<PaymentTransaction> transactions = getInvoicePaymentTransactions(payments, TransactionType.CHARGEBACK);
         Assert.assertEquals(transactions.size(), 0);
     }
 
-    private void createAndVerifyChargeback(final Payment payment) throws KillBillClientException {
+    private void createAndVerifyChargeback(final InvoicePayment payment) throws KillBillClientException {
         // Create the chargeback
         final InvoicePaymentTransaction chargeback = new InvoicePaymentTransaction();
         chargeback.setPaymentId(payment.getPaymentId());
         chargeback.setAmount(BigDecimal.TEN);
 
-        final InvoicePayment chargebackJson = killBillClient.createInvoicePaymentChargeback(chargeback, createdBy, reason, comment);
-        final List<PaymentTransaction> chargebackTransactions = getPaymentTransactions(ImmutableList.of(chargebackJson), TransactionType.CHARGEBACK.toString());
+        final InvoicePayment chargebackJson = invoicePaymentApi.createChargeback(payment.getPaymentId(), chargeback, requestOptions);
+        final List<PaymentTransaction> chargebackTransactions = getInvoicePaymentTransactions(ImmutableList.of(chargebackJson), TransactionType.CHARGEBACK);
         assertEquals(chargebackTransactions.size(), 1);
 
         assertEquals(chargebackTransactions.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
         assertEquals(chargebackTransactions.get(0).getPaymentId(), chargeback.getPaymentId());
 
         // Find the chargeback by account
-        final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(payment.getAccountId());
-        final List<PaymentTransaction> transactions = getPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+        final List<InvoicePayment> payments = accountApi.getInvoicePayments(payment.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final List<PaymentTransaction> transactions = getInvoicePaymentTransactions(payments, TransactionType.CHARGEBACK);
         Assert.assertEquals(transactions.size(), 1);
         assertEquals(transactions.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
         assertEquals(transactions.get(0).getPaymentId(), chargeback.getPaymentId());
     }
 
-    private Payment createAccountWithInvoiceAndPayment() throws Exception {
+    private InvoicePayment createAccountWithInvoiceAndPayment() throws Exception {
         final Invoice invoice = createAccountWithInvoice();
         return getPayment(invoice);
     }
@@ -170,8 +170,8 @@ public class TestChargeback extends TestJaxrsBase {
         final Account accountJson = createAccountWithDefaultPaymentMethod();
 
         // Create subscription
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), "6253283", "Shotgun",
-                                                                ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), "6253283", "Shotgun",
+                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
         // Move after the trial period to trigger an invoice with a non-zero invoice item
@@ -183,7 +183,7 @@ public class TestChargeback extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Retrieve the invoice
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId());
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // We should have two invoices, one for the trial (zero dollar amount) and one for the first month
         assertEquals(invoices.size(), 2);
         assertTrue(invoices.get(1).getAmount().doubleValue() > 0);
@@ -191,8 +191,8 @@ public class TestChargeback extends TestJaxrsBase {
         return invoices.get(1);
     }
 
-    private Payment getPayment(final Invoice invoice) throws KillBillClientException {
-        final InvoicePayments payments = killBillClient.getInvoicePayment(invoice.getInvoiceId());
+    private InvoicePayment getPayment(final Invoice invoice) throws KillBillClientException {
+        final InvoicePayments payments = invoiceApi.getPaymentsForInvoice(invoice.getInvoiceId(), requestOptions);
         assertNotNull(payments);
         assertEquals(payments.size(), 1);
         return payments.get(0);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
index dddb0dc..e414cc2 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
@@ -23,9 +23,10 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Credit;
-import org.killbill.billing.client.model.Invoice;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Credit;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -48,8 +49,6 @@ public class TestCredit extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Can add a credit to an existing invoice")
     public void testAddCreditToInvoice() throws Exception {
-        //final Invoice invoice = killBillClient.getInvoicesForAccount(accountJson.getAccountId()).get(1);
-
         final DateTime effectiveDate = clock.getUTCNow();
         final BigDecimal creditAmount = BigDecimal.ONE;
         final Credit credit = new Credit();
@@ -57,11 +56,11 @@ public class TestCredit extends TestJaxrsBase {
         credit.setCreditAmount(creditAmount);
         credit.setDescription("description");
         credit.setItemDetails("itemDetails");
-        Credit objFromJson = killBillClient.createCredit(credit, false, createdBy, reason, comment);
+        Credit objFromJson = creditApi.createCredit(credit, false, requestOptions);
 
         final UUID invoiceId = objFromJson.getInvoiceId();
         credit.setInvoiceId(invoiceId);
-        objFromJson = killBillClient.createCredit(credit, false, createdBy, reason, comment);
+        objFromJson = creditApi.createCredit(credit, false, requestOptions);
 
         // We can't just compare the object via .equals() due e.g. to the invoice id
         assertEquals(objFromJson.getAccountId(), accountJson.getAccountId());
@@ -74,15 +73,15 @@ public class TestCredit extends TestJaxrsBase {
     @Test(groups = "slow", description = "Can add a credit to an existing account",
             expectedExceptions = KillBillClientException.class, expectedExceptionsMessageRegExp = ".*it is already in COMMITTED status")
     public void testAddCreditToCommittedInvoice() throws Exception {
-        final Invoice invoice = killBillClient.getInvoicesForAccount(accountJson.getAccountId()).get(1);
+        final Invoice invoice = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).get(1);
 
-        final DateTime effectiveDate = clock.getUTCNow();
         final BigDecimal creditAmount = BigDecimal.ONE;
         final Credit credit = new Credit();
         credit.setAccountId(accountJson.getAccountId());
         credit.setInvoiceId(invoice.getInvoiceId());
         credit.setCreditAmount(creditAmount);
-        final Credit objFromJson = killBillClient.createCredit(credit, true, createdBy, reason, comment);
+        final Credit objFromJson = creditApi.createCredit(credit, true, requestOptions);
+        Assert.assertTrue(objFromJson.getCreditAmount().compareTo(creditAmount) == 0);
     }
 
     @Test(groups = "slow", description = "Cannot add a credit if the account doesn't exist")
@@ -92,7 +91,7 @@ public class TestCredit extends TestJaxrsBase {
         credit.setCreditAmount(BigDecimal.TEN);
 
         // Try to create the credit
-        assertNull(killBillClient.createCredit(credit, true, createdBy, reason, comment));
+        assertNull(creditApi.createCredit(credit, true, requestOptions));
     }
 
     @Test(groups = "slow", description = "Cannot credit a badly formatted credit")
@@ -103,7 +102,7 @@ public class TestCredit extends TestJaxrsBase {
 
         // Try to create the credit
         try {
-            killBillClient.createCredit(credit, true, createdBy, reason, comment);
+            creditApi.createCredit(credit, true, requestOptions);
             fail();
         } catch (final KillBillClientException e) {
         }
@@ -111,6 +110,6 @@ public class TestCredit extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Cannot retrieve a non existing credit")
     public void testCreditDoesNotExist() throws Exception {
-        assertNull(killBillClient.getCredit(UUID.randomUUID()));
+        assertNull(creditApi.getCredit(UUID.randomUUID(), requestOptions));
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCustomField.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCustomField.java
index a0fadbb..96cbb8b 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCustomField.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCustomField.java
@@ -26,10 +26,10 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.CustomField;
 import org.killbill.billing.client.model.CustomFields;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.CustomField;
 import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.audit.ChangeType;
 import org.testng.Assert;
@@ -42,16 +42,17 @@ import static org.testng.Assert.assertNotNull;
 
 public class TestCustomField extends TestJaxrsBase {
 
-
     @Test(groups = "slow", description = "Can create/modify/delete custom fields")
     public void testBasicCustomFields() throws Exception {
         final Account account = createAccount();
         final CustomField customField = new CustomField();
         customField.setName("MyName");
         customField.setValue("InitialValue");
-        killBillClient.createAccountCustomField(account.getAccountId(), customField, requestOptions);
+        final CustomFields input = new CustomFields();
+        input.add(customField);
+        accountApi.createAccountCustomFields(account.getAccountId(), input, requestOptions);
 
-        CustomFields allCustomFields = killBillClient.getCustomFields(requestOptions);
+        CustomFields allCustomFields = accountApi.getAccountCustomFields(account.getAccountId(), requestOptions);
         Assert.assertEquals(allCustomFields.size(), 1);
         Assert.assertEquals(allCustomFields.get(0).getName(), "MyName");
         Assert.assertEquals(allCustomFields.get(0).getValue(), "InitialValue");
@@ -59,32 +60,38 @@ public class TestCustomField extends TestJaxrsBase {
         final CustomField customFieldModified = new CustomField();
         customFieldModified.setCustomFieldId(allCustomFields.get(0).getCustomFieldId());
         customFieldModified.setValue("NewValue");
-        killBillClient.modifyAccountCustomFields(account.getAccountId(), ImmutableList.of(customFieldModified), requestOptions);
+        input.clear();
+        input.add(customFieldModified);
+        accountApi.modifyAccountCustomFields(account.getAccountId(), input, requestOptions);
 
-        allCustomFields = killBillClient.getCustomFields(requestOptions);
+        allCustomFields = accountApi.getAccountCustomFields(account.getAccountId(), requestOptions);
         Assert.assertEquals(allCustomFields.size(), 1);
         Assert.assertEquals(allCustomFields.get(0).getName(), "MyName");
         Assert.assertEquals(allCustomFields.get(0).getValue(), "NewValue");
 
-        killBillClient.deleteAccountCustomField(account.getAccountId(), allCustomFields.get(0).getCustomFieldId(), requestOptions);
-        allCustomFields = killBillClient.getCustomFields(requestOptions);
+        accountApi.deleteAccountCustomFields(account.getAccountId(), ImmutableList.<UUID>of(allCustomFields.get(0).getCustomFieldId()), requestOptions);
+        allCustomFields = accountApi.getAccountCustomFields(account.getAccountId(), requestOptions);
         Assert.assertEquals(allCustomFields.size(), 0);
     }
 
-        @Test(groups = "slow", description = "Can paginate through all custom fields")
+    @Test(groups = "slow", description = "Can paginate through all custom fields")
     public void testCustomFieldsPagination() throws Exception {
         final Account account = createAccount();
+
+        final CustomFields input = new CustomFields();
+
         for (int i = 0; i < 5; i++) {
             final CustomField customField = new CustomField();
             customField.setName(UUID.randomUUID().toString().substring(0, 5));
             customField.setValue(UUID.randomUUID().toString().substring(0, 5));
-            killBillClient.createAccountCustomField(account.getAccountId(), customField, requestOptions);
+            input.add(customField);
         }
+        accountApi.createAccountCustomFields(account.getAccountId(), input, requestOptions);
 
-        final CustomFields allCustomFields = killBillClient.getCustomFields(requestOptions);
+        final CustomFields allCustomFields = accountApi.getAccountCustomFields(account.getAccountId(), requestOptions);
         Assert.assertEquals(allCustomFields.size(), 5);
 
-        CustomFields page = killBillClient.getCustomFields(0L, 1L, requestOptions);
+        CustomFields page = customFieldApi.getCustomFields(0L, 1L, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
@@ -99,16 +106,16 @@ public class TestCustomField extends TestJaxrsBase {
             doSearchCustomField(customField.getValue(), customField);
         }
 
-        final CustomFields customFields = killBillClient.searchCustomFields(ObjectType.ACCOUNT.toString(), requestOptions);
+        final CustomFields customFields = customFieldApi.searchCustomFields(ObjectType.ACCOUNT.toString(), requestOptions);
         Assert.assertEquals(customFields.size(), 5);
         Assert.assertEquals(customFields.getPaginationCurrentOffset(), 0);
         Assert.assertEquals(customFields.getPaginationTotalNbRecords(), 5);
         Assert.assertEquals(customFields.getPaginationMaxNbRecords(), 5);
 
-        final CustomFields allAccountCustomFields = killBillClient.getAllAccountCustomFields(account.getAccountId(), null, AuditLevel.FULL, requestOptions);
+        final CustomFields allAccountCustomFields = accountApi.getAllCustomFields(account.getAccountId(), null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(allAccountCustomFields.size(), 5);
 
-        final CustomFields allBundleCustomFieldsForAccount = killBillClient.getAllAccountCustomFields(account.getAccountId(), ObjectType.ACCOUNT.name(), AuditLevel.FULL, requestOptions);
+        final CustomFields allBundleCustomFieldsForAccount = accountApi.getAllCustomFields(account.getAccountId(), ObjectType.ACCOUNT, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(allBundleCustomFieldsForAccount.size(), 5);
     }
 
@@ -120,10 +127,13 @@ public class TestCustomField extends TestJaxrsBase {
         final CustomField customField = new CustomField();
         customField.setName("custom");
         customField.setValue(UUID.randomUUID().toString().substring(0, 5));
-        killBillClient.createAccountCustomField(accountJson.getAccountId(), customField, requestOptions);
+        final CustomFields body = new CustomFields();
+        body.add(customField);
+
+        CustomFields result = accountApi.createAccountCustomFields(accountJson.getAccountId(), body, requestOptions);
 
         // get all audit for the account
-        final List<AuditLog> auditLogsJson = killBillClient.getAccountAuditLogs(accountJson.getAccountId());
+        final List<AuditLog> auditLogsJson = accountApi.getAccountAuditLogs(accountJson.getAccountId(), requestOptions);
         Assert.assertEquals(auditLogsJson.size(), 2);
         UUID objectId = null;
         for (AuditLog auditLog : auditLogsJson) {
@@ -133,7 +143,7 @@ public class TestCustomField extends TestJaxrsBase {
             }
         }
         assertNotNull(objectId);
-        final List<AuditLog> customFieldAuditLogWithHistory = killBillClient.getCustomFieldsAuditLogsWithHistory(accountJson.getAccountId(), objectId);
+        final List<AuditLog> customFieldAuditLogWithHistory = customFieldApi.getCustomFieldAuditLogsWithHistory(result.get(0).getCustomFieldId(), requestOptions);
         assertEquals(customFieldAuditLogWithHistory.size(), 1);
         assertEquals(customFieldAuditLogWithHistory.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(customFieldAuditLogWithHistory.get(0).getObjectType(), ObjectType.CUSTOM_FIELD);
@@ -142,11 +152,10 @@ public class TestCustomField extends TestJaxrsBase {
         final LinkedHashMap history1 = (LinkedHashMap) customFieldAuditLogWithHistory.get(0).getHistory();
         assertNotNull(history1);
         assertEquals(history1.get("fieldName"), "custom");
-
     }
 
     private void doSearchCustomField(final String searchKey, @Nullable final CustomField expectedCustomField) throws KillBillClientException {
-        final CustomFields customFields = killBillClient.searchCustomFields(searchKey, requestOptions);
+        final CustomFields customFields = customFieldApi.searchCustomFields(searchKey, requestOptions);
         if (expectedCustomField == null) {
             Assert.assertTrue(customFields.isEmpty());
             Assert.assertEquals(customFields.getPaginationCurrentOffset(), 0);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index 5324b13..ae19577 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -34,14 +34,16 @@ import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.BulkBaseSubscriptionAndAddOns;
-import org.killbill.billing.client.model.Bundle;
+import org.killbill.billing.client.model.BulkSubscriptionsBundles;
 import org.killbill.billing.client.model.Bundles;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.PhasePriceOverride;
-import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.Subscriptions;
 import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.BulkSubscriptionsBundle;
+import org.killbill.billing.client.model.gen.Bundle;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.PhasePriceOverride;
+import org.killbill.billing.client.model.gen.Subscription;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
@@ -60,8 +62,6 @@ import static org.testng.Assert.assertTrue;
 
 public class TestEntitlement extends TestJaxrsBase {
 
-    private static final int CALL_COMPLETION_TIMEOUT_SEC = 5;
-
     @Test(groups = "slow", description = "Can change plan and cancel a subscription")
     public void testEntitlementInTrialOk() throws Exception {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
@@ -72,11 +72,11 @@ public class TestEntitlement extends TestJaxrsBase {
         final String productName = "Shotgun";
         final BillingPeriod term = BillingPeriod.MONTHLY;
 
-        final Subscription entitlementJson = createEntitlement(accountJson.getAccountId(), "99999", productName,
-                                                               ProductCategory.BASE, term, true);
+        final Subscription entitlementJson = createSubscription(accountJson.getAccountId(), "99999", productName,
+                                                                ProductCategory.BASE, term, true);
 
         // Retrieves with GET
-        Subscription objFromJson = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        Subscription objFromJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         Assert.assertEquals(objFromJson.getPriceOverrides().size(), 2);
         Assert.assertEquals(objFromJson.getPriceOverrides().get(0).getFixedPrice(), BigDecimal.ZERO);
         Assert.assertNull(objFromJson.getPriceOverrides().get(0).getRecurringPrice());
@@ -104,7 +104,7 @@ public class TestEntitlement extends TestJaxrsBase {
         newInput.setBillingPeriod(entitlementJson.getBillingPeriod());
         newInput.setPriceList(entitlementJson.getPriceList());
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_CHANGE, ExtBusEventType.SUBSCRIPTION_CHANGE, ExtBusEventType.INVOICE_CREATION);
-        objFromJson = killBillClient.updateSubscription(newInput, CALL_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.changeSubscriptionPlan(entitlementJson.getSubscriptionId(), newInput, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
         Assert.assertNotNull(objFromJson);
 
@@ -117,10 +117,10 @@ public class TestEntitlement extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Cancel IMM (Billing EOT)
-        killBillClient.cancelSubscription(newInput.getSubscriptionId(), CALL_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.cancelSubscriptionPlan(newInput.getSubscriptionId(), null, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // Retrieves to check EndDate
-        objFromJson = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        objFromJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         assertNotNull(objFromJson.getCancelledDate());
         assertTrue(objFromJson.getCancelledDate().compareTo(new LocalDate(clock.getUTCNow())) == 0);
     }
@@ -135,11 +135,11 @@ public class TestEntitlement extends TestJaxrsBase {
         final String productName = "Shotgun";
         final BillingPeriod term = BillingPeriod.MONTHLY;
 
-        final Subscription entitlementJson = createEntitlement(accountJson.getAccountId(), "99999", productName,
-                                                               ProductCategory.BASE, term, true);
+        final Subscription entitlementJson = createSubscription(accountJson.getAccountId(), "99999", productName,
+                                                                ProductCategory.BASE, term, true);
 
         // Retrieves with GET
-        Subscription objFromJson = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        Subscription objFromJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         Assert.assertEquals(objFromJson.getPriceOverrides().size(), 2);
         Assert.assertEquals(objFromJson.getPriceOverrides().get(0).getPhaseName(), "shotgun-monthly-trial");
         Assert.assertEquals(objFromJson.getPriceOverrides().get(0).getFixedPrice(), BigDecimal.ZERO);
@@ -163,11 +163,11 @@ public class TestEntitlement extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Cancel EOT
-        killBillClient.cancelSubscription(entitlementJson.getSubscriptionId(), EntitlementActionPolicy.END_OF_TERM,
-                                          BillingActionPolicy.END_OF_TERM, CALL_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.cancelSubscriptionPlan(entitlementJson.getSubscriptionId(), null, EntitlementActionPolicy.END_OF_TERM,
+                                               BillingActionPolicy.END_OF_TERM, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // Retrieves to check EndDate
-        objFromJson = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        objFromJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         assertNotNull(objFromJson.getCancelledDate());
         Assert.assertEquals(objFromJson.getPriceOverrides().size(), 2);
         Assert.assertEquals(objFromJson.getPriceOverrides().get(0).getPhaseName(), "shotgun-monthly-trial");
@@ -178,9 +178,9 @@ public class TestEntitlement extends TestJaxrsBase {
         Assert.assertEquals(objFromJson.getPriceOverrides().get(1).getRecurringPrice(), new BigDecimal("249.95"));
 
         // Uncancel
-        killBillClient.uncancelSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        subscriptionApi.uncancelSubscriptionPlan(entitlementJson.getSubscriptionId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        objFromJson = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        objFromJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         assertNull(objFromJson.getCancelledDate());
         Assert.assertEquals(objFromJson.getPriceOverrides().size(), 2);
         Assert.assertEquals(objFromJson.getPriceOverrides().get(0).getPhaseName(), "shotgun-monthly-trial");
@@ -202,11 +202,11 @@ public class TestEntitlement extends TestJaxrsBase {
         subscription.setBillingPeriod(BillingPeriod.ANNUAL);
         subscription.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        assertNull(killBillClient.updateSubscription(subscription, CALL_COMPLETION_TIMEOUT_SEC, requestOptions));
+        subscriptionApi.changeSubscriptionPlan(subscriptionId, subscription, null, null, null, requestOptions);
 
-        killBillClient.cancelSubscription(subscriptionId, requestOptions);
+        subscriptionApi.cancelSubscriptionPlan(subscriptionId, null, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        assertNull(killBillClient.getSubscription(subscriptionId, requestOptions));
+        assertNull(subscriptionApi.getSubscription(subscriptionId, requestOptions));
     }
 
     @Test(groups = "slow", description = "Can override billing policy on change")
@@ -219,11 +219,11 @@ public class TestEntitlement extends TestJaxrsBase {
         final String productName = "Shotgun";
         final BillingPeriod term = BillingPeriod.ANNUAL;
 
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), "99999", productName,
-                                                                ProductCategory.BASE, term, true);
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), "99999", productName,
+                                                                 ProductCategory.BASE, term, true);
 
         // Retrieves with GET
-        Subscription objFromJson = killBillClient.getSubscription(subscriptionJson.getSubscriptionId(), requestOptions);
+        Subscription objFromJson = subscriptionApi.getSubscription(subscriptionJson.getSubscriptionId(), requestOptions);
         // Equality in java client is not correctly implemented so manually check PriceOverrides section and then reset before equality
         objFromJson.setPriceOverrides(null);
         subscriptionJson.setPriceOverrides(null);
@@ -239,8 +239,9 @@ public class TestEntitlement extends TestJaxrsBase {
         newInput.setProductCategory(ProductCategory.BASE);
         newInput.setBillingPeriod(BillingPeriod.MONTHLY);
         newInput.setPriceList(subscriptionJson.getPriceList());
-        objFromJson = killBillClient.updateSubscription(newInput, BillingActionPolicy.IMMEDIATE, CALL_COMPLETION_TIMEOUT_SEC, requestOptions );
-        Assert.assertNotNull(objFromJson);
+        subscriptionApi.changeSubscriptionPlan(subscriptionJson.getSubscriptionId(), newInput, null, BillingActionPolicy.IMMEDIATE, NULL_PLUGIN_PROPERTIES, requestOptions);
+
+        objFromJson = subscriptionApi.getSubscription(subscriptionJson.getSubscriptionId(), requestOptions);
         assertEquals(objFromJson.getBillingPeriod(), BillingPeriod.MONTHLY);
     }
 
@@ -272,31 +273,30 @@ public class TestEntitlement extends TestJaxrsBase {
                                            ExtBusEventType.INVOICE_CREATION,
                                            ExtBusEventType.INVOICE_PAYMENT_SUCCESS,
                                            ExtBusEventType.PAYMENT_SUCCESS);
-        final Subscription subscription = killBillClient.createSubscription(input, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        final Subscription subscription = subscriptionApi.createSubscription(input, null, null, null, null, null, true, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
         Assert.assertEquals(subscription.getPriceOverrides().size(), 2);
 
         Assert.assertEquals(subscription.getEvents().size(), 3);
-        Assert.assertEquals(subscription.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT.name());
+        Assert.assertEquals(subscription.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT);
         assertMatches(subscription.getEvents().get(0).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription.getEvents().get(0).getPhase(), "shotgun-monthly-[1-9]+-trial");
-        Assert.assertEquals(subscription.getEvents().get(0).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
+        Assert.assertEquals(subscription.getEvents().get(0).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
         Assert.assertEquals(subscription.getEvents().get(0).getProduct(), "Shotgun");
 
-        Assert.assertEquals(subscription.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING.name());
+        Assert.assertEquals(subscription.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING);
         assertMatches(subscription.getEvents().get(1).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription.getEvents().get(1).getPhase(), "shotgun-monthly-[1-9]+-trial");
-        Assert.assertEquals(subscription.getEvents().get(1).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
+        Assert.assertEquals(subscription.getEvents().get(1).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
         Assert.assertEquals(subscription.getEvents().get(1).getProduct(), "Shotgun");
 
-        Assert.assertEquals(subscription.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE.name());
+        Assert.assertEquals(subscription.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE);
         assertMatches(subscription.getEvents().get(2).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription.getEvents().get(2).getPhase(), "shotgun-monthly-[1-9]+-evergreen");
-        Assert.assertEquals(subscription.getEvents().get(2).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
+        Assert.assertEquals(subscription.getEvents().get(2).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
         Assert.assertEquals(subscription.getEvents().get(2).getProduct(), "Shotgun");
 
-
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.FULL, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.FULL, requestOptions);
         assertEquals(invoices.size(), 1);
         assertEquals(invoices.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
 
@@ -308,7 +308,7 @@ public class TestEntitlement extends TestJaxrsBase {
         clock.addDays(30);
         callbackServlet.assertListenerStatus();
 
-        final Subscription subscription2 = killBillClient.getSubscription(subscription.getSubscriptionId(), requestOptions);
+        final Subscription subscription2 = subscriptionApi.getSubscription(subscription.getSubscriptionId(), requestOptions);
         Assert.assertEquals(subscription2.getEvents().size(), 3);
 
         clock.addDays(3);
@@ -317,28 +317,29 @@ public class TestEntitlement extends TestJaxrsBase {
         final Subscription newInput = new Subscription();
         newInput.setSubscriptionId(subscription2.getSubscriptionId());
         newInput.setPlanName("pistol-monthly");
-        final Subscription subscription3 = killBillClient.updateSubscription(newInput, null, BillingActionPolicy.IMMEDIATE, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.changeSubscriptionPlan(subscription2.getSubscriptionId(), newInput, null, BillingActionPolicy.IMMEDIATE, NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Subscription subscription3 = subscriptionApi.getSubscription(subscription.getSubscriptionId(), requestOptions);
 
         Assert.assertEquals(subscription3.getEvents().size(), 4);
-        Assert.assertEquals(subscription3.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT.name());
+        Assert.assertEquals(subscription3.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT);
         assertMatches(subscription3.getEvents().get(0).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription3.getEvents().get(0).getPhase(), "shotgun-monthly-[1-9]+-trial");
         Assert.assertEquals(subscription3.getEvents().get(0).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
         Assert.assertEquals(subscription3.getEvents().get(0).getProduct(), "Shotgun");
 
-        Assert.assertEquals(subscription3.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING.name());
+        Assert.assertEquals(subscription3.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING);
         assertMatches(subscription3.getEvents().get(1).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription3.getEvents().get(1).getPhase(), "shotgun-monthly-[1-9]+-trial");
         Assert.assertEquals(subscription3.getEvents().get(1).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
         Assert.assertEquals(subscription3.getEvents().get(1).getProduct(), "Shotgun");
 
-        Assert.assertEquals(subscription3.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE.name());
+        Assert.assertEquals(subscription3.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE);
         assertMatches(subscription3.getEvents().get(2).getPlan(), "shotgun-monthly-[1-9]+");
         assertMatches(subscription3.getEvents().get(2).getPhase(), "shotgun-monthly-[1-9]+-evergreen");
         Assert.assertEquals(subscription3.getEvents().get(2).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
         Assert.assertEquals(subscription3.getEvents().get(2).getProduct(), "Shotgun");
 
-        Assert.assertEquals(subscription3.getEvents().get(3).getEventType(), SubscriptionEventType.CHANGE.name());
+        Assert.assertEquals(subscription3.getEvents().get(3).getEventType(), SubscriptionEventType.CHANGE);
         Assert.assertEquals(subscription3.getEvents().get(3).getPlan(), "pistol-monthly");
         Assert.assertEquals(subscription3.getEvents().get(3).getPhase(), "pistol-monthly-evergreen");
         Assert.assertEquals(subscription3.getEvents().get(3).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
@@ -378,39 +379,39 @@ public class TestEntitlement extends TestJaxrsBase {
         addOn2.setBillingPeriod(BillingPeriod.MONTHLY);
         addOn2.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        final List<Subscription> subscriptions = new ArrayList<Subscription>();
+        final Subscriptions subscriptions = new Subscriptions();
         subscriptions.add(base);
         subscriptions.add(addOn1);
         subscriptions.add(addOn2);
 
-        final Bundle bundle = killBillClient.createSubscriptionWithAddOns(subscriptions, null, 10, requestOptions);
+        final Bundle bundle = subscriptionApi.createSubscriptionWithAddOns(subscriptions, null, null, null, null, true, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(bundle);
         assertEquals(bundle.getExternalKey(), "base");
         assertEquals(bundle.getSubscriptions().size(), 3);
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoices.size(), 1);
         assertEquals(invoices.get(0).getBalance().compareTo(BigDecimal.ZERO), 1);
-        assertEquals(killBillClient.getInvoiceTags(invoices.get(0).getInvoiceId(), requestOptions).size(), 0);
+        assertEquals(invoiceApi.getInvoiceTags(invoices.get(0).getInvoiceId(), requestOptions).size(), 0);
 
-        final Bundles accountBundles = killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions);
+        final Bundles accountBundles = accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions);
         assertEquals(accountBundles.size(), 1);
         for (final Subscription subscription : accountBundles.get(0).getSubscriptions()) {
             assertEquals(subscription.getState(), EntitlementState.ACTIVE);
         }
 
-        killBillClient.closeAccount(accountJson.getAccountId(), true, true, false, requestOptions);
+        accountApi.closeAccount(accountJson.getAccountId(), true, true, false, true, requestOptions);
 
-        final Bundles accountBundlesAfterClose = killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions);
+        final Bundles accountBundlesAfterClose = accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions);
         assertEquals(accountBundlesAfterClose.size(), 1);
         for (final Subscription subscription : accountBundlesAfterClose.get(0).getSubscriptions()) {
             assertEquals(subscription.getState(), EntitlementState.CANCELLED);
         }
 
-        final List<Invoice> invoicesAfterClose = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, requestOptions);
+        final List<Invoice> invoicesAfterClose = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoicesAfterClose.size(), 1);
         assertEquals(invoicesAfterClose.get(0).getBalance().compareTo(BigDecimal.ZERO), 0);
-        assertEquals(killBillClient.getInvoiceTags(invoicesAfterClose.get(0).getInvoiceId(), requestOptions).size(), 1);
+        assertEquals(invoiceApi.getInvoiceTags(invoicesAfterClose.get(0).getInvoiceId(), requestOptions).size(), 1);
     }
 
     @Test(groups = "slow", description = "Create a bulk of base entitlement and addOns under the same transaction")
@@ -446,9 +447,12 @@ public class TestEntitlement extends TestJaxrsBase {
         subscriptions.add(addOn1);
         subscriptions.add(addOn2);
 
-        final List<BulkBaseSubscriptionAndAddOns> bulkList = new ArrayList<BulkBaseSubscriptionAndAddOns>();
-        bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
-        bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+        final BulkSubscriptionsBundle bulkList = new BulkSubscriptionsBundle();
+        bulkList.setBaseEntitlementAndAddOns(subscriptions);
+
+        final BulkSubscriptionsBundles input = new BulkSubscriptionsBundles();
+        input.add(bulkList);
+        input.add(bulkList);
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.ACCOUNT_CHANGE,
                                            ExtBusEventType.ENTITLEMENT_CREATION,
@@ -471,19 +475,19 @@ public class TestEntitlement extends TestJaxrsBase {
                                            ExtBusEventType.SUBSCRIPTION_CREATION,
                                            ExtBusEventType.INVOICE_CREATION,
                                            ExtBusEventType.INVOICE_PAYMENT_FAILED);
-        final Bundles bundles = killBillClient.createSubscriptionsWithAddOns(bulkList, null, 10, requestOptions);
+        final Bundles bundles = subscriptionApi.createSubscriptionsWithAddOns(input, null, null, false, false, true, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES, requestOptions);
         callbackServlet.assertListenerStatus();
 
         assertNotNull(bundles);
         assertEquals(bundles.size(), 2);
         assertFalse(bundles.get(0).getExternalKey().equals(bundles.get(1).getExternalKey()));
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 1);
         assertEquals(invoices.get(0).getBalance().compareTo(BigDecimal.ZERO), 1);
-        assertEquals(killBillClient.getInvoiceTags(invoices.get(0).getInvoiceId(), requestOptions).size(), 0);
+        assertEquals(invoiceApi.getInvoiceTags(invoices.get(0).getInvoiceId(), requestOptions).size(), 0);
 
-        final Bundles accountBundles = killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions);
+        final Bundles accountBundles = accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions);
         assertEquals(accountBundles.size(), 2);
         for (final Bundle bundle : accountBundles) {
             for (final Subscription subscription : bundle.getSubscriptions()) {
@@ -519,10 +523,10 @@ public class TestEntitlement extends TestJaxrsBase {
                                            ExtBusEventType.INVOICE_ADJUSTMENT,
                                            ExtBusEventType.INVOICE_ADJUSTMENT,
                                            ExtBusEventType.BLOCKING_STATE);
-        killBillClient.closeAccount(accountJson.getAccountId(), true, false, true, requestOptions);
+        accountApi.closeAccount(accountJson.getAccountId(), true, false, true, true, requestOptions);
         callbackServlet.assertListenerStatus();
 
-        final Bundles accountBundlesAfterClose = killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions);
+        final Bundles accountBundlesAfterClose = accountApi.getAccountBundles(accountJson.getAccountId(), null, null, requestOptions);
         assertEquals(accountBundlesAfterClose.size(), 2);
         for (final Bundle bundle : accountBundlesAfterClose) {
             for (final Subscription subscription : bundle.getSubscriptions()) {
@@ -530,15 +534,15 @@ public class TestEntitlement extends TestJaxrsBase {
             }
         }
 
-        final List<Invoice> invoicesAfterClose = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, requestOptions);
+        final List<Invoice> invoicesAfterClose = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoicesAfterClose.size(), 2);
         assertEquals(invoicesAfterClose.get(0).getBalance().compareTo(BigDecimal.ZERO), 0);
-        assertEquals(killBillClient.getInvoiceTags(invoicesAfterClose.get(0).getInvoiceId(), requestOptions).size(), 0);
+        assertEquals(invoiceApi.getInvoiceTags(invoicesAfterClose.get(0).getInvoiceId(), requestOptions).size(), 0);
     }
 
     @Test(groups = "slow", description = "Create a bulk of base entitlements and addOns under the same transaction",
             expectedExceptions = KillBillClientException.class, expectedExceptionsMessageRegExp = "SubscriptionJson productName needs to be set when no planName is specified")
-    public void testCreateEntitlementsWithoutBase() throws Exception {
+    public void testcreateSubscriptionsWithoutBase() throws Exception {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
@@ -560,14 +564,19 @@ public class TestEntitlement extends TestJaxrsBase {
         subscriptions.add(bp);
         subscriptions.add(addOn1);
 
-        final List<BulkBaseSubscriptionAndAddOns> bulkList = new ArrayList<BulkBaseSubscriptionAndAddOns>();
-        bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
-        bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+        final BulkSubscriptionsBundle bulkList1 = new BulkSubscriptionsBundle();
+        bulkList1.setBaseEntitlementAndAddOns(subscriptions);
+        final BulkSubscriptionsBundle bulkList2 = new BulkSubscriptionsBundle();
+        bulkList2.setBaseEntitlementAndAddOns(subscriptions);
+
+        final BulkSubscriptionsBundles input = new BulkSubscriptionsBundles();
+        input.add(bulkList1);
+        input.add(bulkList2);
 
-        killBillClient.createSubscriptionsWithAddOns(bulkList, null, 10, requestOptions);
+        subscriptionApi.createSubscriptionsWithAddOns(input, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
     }
 
-    @Test(groups = "slow", description = "Create addOns in a bundle where BP subscription already exists")
+    @Test(groups = "slow", description = "Create addOns in a bundle where BP subscription already exist")
     public void testEntitlementsWithAddOnsAndAlreadyExistingBP() throws Exception {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
@@ -581,7 +590,7 @@ public class TestEntitlement extends TestJaxrsBase {
         input.setProductCategory(ProductCategory.BASE);
         input.setBillingPeriod(BillingPeriod.MONTHLY);
         input.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
-        final Subscription subscription = killBillClient.createSubscription(input, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        final Subscription subscription = subscriptionApi.createSubscription(input, null, null, null, null, null, true, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         final Subscription addOn1 = new Subscription();
         addOn1.setAccountId(accountJson.getAccountId());
@@ -603,19 +612,23 @@ public class TestEntitlement extends TestJaxrsBase {
         subscriptions.add(addOn1);
         subscriptions.add(addOn2);
 
-        final Iterable<BulkBaseSubscriptionAndAddOns> bulkBaseSubscriptionAndAddOns = ImmutableList.of(new BulkBaseSubscriptionAndAddOns(subscriptions));
+        final BulkSubscriptionsBundles bulkSubscriptionsBundles = new BulkSubscriptionsBundles();
 
-        final Bundles bundles = killBillClient.createSubscriptionsWithAddOns(bulkBaseSubscriptionAndAddOns, null, 10, requestOptions);
+        final BulkSubscriptionsBundle bulkSubscriptionsBundle = new BulkSubscriptionsBundle();
+        bulkSubscriptionsBundle.setBaseEntitlementAndAddOns(subscriptions);
+        bulkSubscriptionsBundles.add(bulkSubscriptionsBundle);
+
+        final Bundles bundles = subscriptionApi.createSubscriptionsWithAddOns(bulkSubscriptionsBundles, null, null, false, false, true, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(bundles);
         assertEquals(bundles.size(), 1);
         assertEquals(bundles.get(0).getSubscriptions().size(), 3);
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.FULL, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoices.size(), 2);
     }
 
     @Test(groups = "slow", description = "Can create an entitlement in the future")
-    public void testCreateEntitlementInTheFuture() throws Exception {
+    public void testcreateSubscriptionInTheFuture() throws Exception {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
@@ -627,7 +640,7 @@ public class TestEntitlement extends TestJaxrsBase {
         input.setProductCategory(ProductCategory.BASE);
         input.setBillingPeriod(BillingPeriod.MONTHLY);
         input.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
-        final Subscription entitlementJson = killBillClient.createSubscription(input, initialDate.toLocalDate().plusMonths(1), -1, requestOptions);
+        final Subscription entitlementJson = subscriptionApi.createSubscription(input, initialDate.toLocalDate().plusMonths(1), null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         Assert.assertEquals(entitlementJson.getProductName(), input.getProductName());
         Assert.assertEquals(entitlementJson.getProductCategory(), input.getProductCategory());
@@ -635,7 +648,7 @@ public class TestEntitlement extends TestJaxrsBase {
         Assert.assertEquals(entitlementJson.getPriceList(), input.getPriceList());
 
         // Retrieves with GET
-        final Subscription subscription = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        final Subscription subscription = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         Assert.assertTrue(subscription.equals(entitlementJson));
         Assert.assertEquals(subscription.getPriceOverrides().size(), 2);
         Assert.assertEquals(subscription.getPriceOverrides().get(0).getPhaseName(), "shotgun-monthly-trial");
@@ -647,17 +660,17 @@ public class TestEntitlement extends TestJaxrsBase {
     }
 
     @Test(groups = "slow", description = "Can create an entitlement with an account with autoPayOff")
-    public void testCreateEntitlementWithAutoPayOff() throws Exception {
+    public void testcreateSubscriptionWithAutoPayOff() throws Exception {
         final Account accountJson = createAccount();
         assertNotNull(accountJson);
 
         // assign autoPaymentOff tag to account
-        Tags tags = killBillClient.createAccountTag(accountJson.getAccountId(), new UUID(0L, 1L), requestOptions);
+        Tags tags = accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(new UUID(0L, 1L)), requestOptions);
         assertEquals(tags.get(0).getTagDefinitionName(), "AUTO_PAY_OFF");
 
         // verify that number of invoices and payments for account is still 0
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 0);
-        assertEquals(killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions).size(), 0);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 0);
+        assertEquals(accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
 
         // create a subscription with no trial plan
         final Subscription input = new Subscription();
@@ -666,14 +679,15 @@ public class TestEntitlement extends TestJaxrsBase {
         input.setProductCategory(ProductCategory.BASE);
         input.setBillingPeriod(BillingPeriod.MONTHLY);
         input.setPriceList("notrial");
-        final Subscription subscriptionJson = killBillClient.createSubscription(input, null, 10, requestOptions);
+
+        final Subscription subscriptionJson = subscriptionApi.createSubscription(input, null, null, null, null, null, true, 10L, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(subscriptionJson);
 
         // verify that number of invoices is now 1
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 1);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 1);
 
         // verify that number of payments is still 0 (no attempts)
-        assertEquals(killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions).size(), 0);
+        assertEquals(accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
     }
 
     @Test(groups = "slow", description = "Verify we can move the BCD associated with the subscription")
@@ -686,8 +700,8 @@ public class TestEntitlement extends TestJaxrsBase {
         final String productName = "Shotgun";
         final BillingPeriod term = BillingPeriod.MONTHLY;
 
-        final Subscription entitlementJson = createEntitlement(accountJson.getAccountId(), "99999", productName,
-                                                               ProductCategory.BASE, term, true);
+        final Subscription entitlementJson = createSubscription(accountJson.getAccountId(), "99999", productName,
+                                                                ProductCategory.BASE, term, true);
 
         Assert.assertEquals(entitlementJson.getBillCycleDayLocal(), new Integer(25));
 
@@ -695,10 +709,10 @@ public class TestEntitlement extends TestJaxrsBase {
         updatedSubscription.setSubscriptionId(entitlementJson.getSubscriptionId());
         updatedSubscription.setBillCycleDayLocal(9);
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_BCD_CHANGE);
-        killBillClient.updateSubscriptionBCD(updatedSubscription, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.updateSubscriptionBCD(entitlementJson.getSubscriptionId(), updatedSubscription, null, requestOptions);
         callbackServlet.assertListenerStatus();
 
-        final Subscription result = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        final Subscription result = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         // Still shows as the 4 (BCD did not take effect)
         Assert.assertEquals(result.getBillCycleDayLocal(), new Integer(25));
 
@@ -707,7 +721,7 @@ public class TestEntitlement extends TestJaxrsBase {
         clock.addDays(14);
         callbackServlet.assertListenerStatus();
 
-        final Subscription result2 = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        final Subscription result2 = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         // Still shows as the 4 (BCD did not take effect)
         Assert.assertEquals(result2.getBillCycleDayLocal(), new Integer(9));
     }
@@ -724,18 +738,18 @@ public class TestEntitlement extends TestJaxrsBase {
         input.setExternalKey("somethingSpecial");
         input.setPlanName("shotgun-monthly");
 
-        final Subscription entitlementJson = killBillClient.createSubscription(input, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        final Subscription entitlementJson = subscriptionApi.createSubscription(input, null, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(entitlementJson.getProductName(), "Shotgun");
         Assert.assertEquals(entitlementJson.getBillingPeriod(), BillingPeriod.MONTHLY);
         Assert.assertEquals(entitlementJson.getPriceList(), DefaultPriceListSet.DEFAULT_PRICELIST_NAME);
         Assert.assertEquals(entitlementJson.getPlanName(), "shotgun-monthly");
 
-
         final Subscription newInput = new Subscription();
         newInput.setAccountId(entitlementJson.getAccountId());
         newInput.setSubscriptionId(entitlementJson.getSubscriptionId());
         newInput.setPlanName("pistol-monthly");
-        final Subscription newEntitlementJson = killBillClient.updateSubscription(newInput, null, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.changeSubscriptionPlan(entitlementJson.getSubscriptionId(), newInput, null, null, NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Subscription newEntitlementJson = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         Assert.assertEquals(newEntitlementJson.getProductName(), "Pistol");
         Assert.assertEquals(newEntitlementJson.getBillingPeriod(), BillingPeriod.MONTHLY);
         Assert.assertEquals(newEntitlementJson.getPriceList(), DefaultPriceListSet.DEFAULT_PRICELIST_NAME);
@@ -752,10 +766,8 @@ public class TestEntitlement extends TestJaxrsBase {
         final String productName = "Shotgun";
         final BillingPeriod term = BillingPeriod.MONTHLY;
 
-        final Subscription entitlementJson = createEntitlement(accountJson.getAccountId(), "99999", productName,
-                                                               ProductCategory.BASE, term, true);
-
-
+        final Subscription entitlementJson = createSubscription(accountJson.getAccountId(), "99999", productName,
+                                                                ProductCategory.BASE, term, true);
 
         // Change plan in the future
         final String newProductName = "Assault-Rifle";
@@ -769,15 +781,15 @@ public class TestEntitlement extends TestJaxrsBase {
         newInput.setPriceList(entitlementJson.getPriceList());
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_CHANGE);
-        Subscription  refreshedSubscription = killBillClient.updateSubscription(newInput, new LocalDate(2012, 4, 28),  null, CALL_COMPLETION_TIMEOUT_SEC, requestOptions);
+        subscriptionApi.changeSubscriptionPlan(entitlementJson.getSubscriptionId(), newInput, new LocalDate(2012, 4, 28), null, NULL_PLUGIN_PROPERTIES, requestOptions);
+        Subscription refreshedSubscription = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         callbackServlet.assertListenerStatus();
         Assert.assertNotNull(refreshedSubscription);
 
-
         final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(1));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        killBillClient.undoChangePlan(refreshedSubscription.getSubscriptionId(), requestOptions);
+        subscriptionApi.undoChangeSubscriptionPlan(refreshedSubscription.getSubscriptionId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // MOVE AFTER TRIAL
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE,
@@ -788,7 +800,7 @@ public class TestEntitlement extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Retrieves to check EndDate
-        refreshedSubscription = killBillClient.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
+        refreshedSubscription = subscriptionApi.getSubscription(entitlementJson.getSubscriptionId(), requestOptions);
         Assert.assertEquals(refreshedSubscription.getPriceOverrides().size(), 2);
         Assert.assertEquals(refreshedSubscription.getPriceOverrides().get(0).getPhaseName(), "shotgun-monthly-trial");
         Assert.assertEquals(refreshedSubscription.getPriceOverrides().get(0).getFixedPrice(), BigDecimal.ZERO);
@@ -799,6 +811,4 @@ public class TestEntitlement extends TestJaxrsBase {
 
     }
 
-
-
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
index fa7c31f..e02ef9c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
@@ -23,9 +23,9 @@ import java.util.List;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -34,16 +34,16 @@ import static org.testng.Assert.fail;
 
 public class TestExceptions extends TestJaxrsBase {
 
-    @Test(groups = "slow", enabled = false)
+    @Test(groups = "slow", enabled=false)
     public void testExceptionMapping() throws Exception {
         final Account account = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(account.getAccountId());
+        final List<InvoicePayment> payments = accountApi.getInvoicePayments(account.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
         final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
         input.setPaymentId(payments.get(0).getPaymentId());
         input.setAmount(BigDecimal.TEN.negate());
         try {
-            killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
+            invoicePaymentApi.createChargeback(payments.get(0).getPaymentId(), input, requestOptions);
             fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getBillingException().getClassName(), InvoiceApiException.class.getName());
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExportAccount.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExportAccount.java
new file mode 100644
index 0000000..7a26a04
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExportAccount.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.jaxrs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.killbill.billing.client.model.gen.Account;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class TestExportAccount extends TestJaxrsBase {
+
+    @Test(groups = "slow")
+    public void testExportAccount() throws Exception {
+        final Account emptyAccount = new Account();
+        final Account account = accountApi.createAccount(emptyAccount, requestOptions);
+        final OutputStream outputStream = new ByteArrayOutputStream();
+        final int statusCode = exportApi.exportDataForAccount(account.getAccountId(), outputStream, requestOptions);
+        outputStream.flush();
+        Assert.assertEquals(statusCode, 200);
+    }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java
index 80575fd..6ad533c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java
@@ -23,19 +23,20 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoiceItem;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
 import org.killbill.billing.client.model.InvoicePayments;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
 import org.killbill.billing.client.model.Payments;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoiceItem;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.util.api.AuditLevel;
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.assertEquals;
@@ -50,20 +51,19 @@ public class TestExternalRefund extends TestJaxrsBase {
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
 
-        Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
-        final List<InvoiceItem> itemsToBeAdjusted = invoices.get(1).getItems();
+        Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
 
         // regular refund
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
-        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency());
         invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
-        final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, requestOptions);
-        assertNotNull(invoicePaymentRefund);
+        invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), invoicePaymentTransactionRequest, payment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
+        final InvoicePayment invoicePaymentRefund = invoicePaymentApi.getInvoicePayment(payment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertSingleInvoicePaymentRefund(invoicePaymentRefund);
         assertRefundInvoiceNoAdjustments(accountJson.getAccountId());
         assertRefundAccountBalance(accountJson.getAccountId(), BigDecimal.valueOf(249.95), BigDecimal.ZERO);
@@ -75,20 +75,21 @@ public class TestExternalRefund extends TestJaxrsBase {
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
 
-        Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+        Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
         final List<InvoiceItem> itemsToBeAdjusted = invoices.get(1).getItems();
 
         // regular refund
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
-        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency());
         invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
         invoicePaymentTransactionRequest.setIsAdjusted(true);
         invoicePaymentTransactionRequest.setAdjustments(itemsToBeAdjusted);
-        final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, requestOptions);
+        invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), invoicePaymentTransactionRequest, payment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final InvoicePayment invoicePaymentRefund = invoicePaymentApi.getInvoicePayment(payment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentRefund);
 
         assertSingleInvoicePaymentRefund(invoicePaymentRefund);
@@ -103,26 +104,26 @@ public class TestExternalRefund extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithExternalPMBundleAndSubscriptionAndManualPayTagAndWaitForFirstInvoice();
 
-        final Invoices invoicesForAccount = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoicesForAccount = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         final Invoice unpaidInvoice = invoicesForAccount.get(1);
         assertEquals(unpaidInvoice.getBalance().compareTo(BigDecimal.valueOf(249.95)), 0);
 
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentsForAccount.size(), 0);
 
         final InvoicePayment invoicePaymentRequest = new InvoicePayment();
         invoicePaymentRequest.setTargetInvoiceId(unpaidInvoice.getInvoiceId());
         invoicePaymentRequest.setAccountId(accountJson.getAccountId());
-        invoicePaymentRequest.setCurrency(unpaidInvoice.getCurrency().toString());
+        invoicePaymentRequest.setCurrency(unpaidInvoice.getCurrency());
         invoicePaymentRequest.setPurchasedAmount(unpaidInvoice.getAmount());
-        final InvoicePayment invoicePayment = killBillClient.createInvoicePayment(invoicePaymentRequest, true, requestOptions);
+        final InvoicePayment invoicePayment = invoiceApi.createInstantPayment(unpaidInvoice.getInvoiceId(), invoicePaymentRequest, true, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(invoicePayment.getPurchasedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
         assertEquals(invoicePayment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
 
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
         invoicePaymentTransactionRequest.setPaymentId(invoicePayment.getPaymentId());
-        final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, requestOptions);
+        final InvoicePayment invoicePaymentRefund = invoicePaymentApi.createRefundWithAdjustments(invoicePayment.getPaymentId(), invoicePaymentTransactionRequest, invoicePayment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentRefund);
 
         assertSingleInvoicePaymentRefund(invoicePaymentRefund);
@@ -137,19 +138,19 @@ public class TestExternalRefund extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithExternalPMBundleAndSubscriptionAndManualPayTagAndWaitForFirstInvoice();
 
-        final Invoices invoicesForAccount = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoicesForAccount = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         final Invoice unpaidInvoice = invoicesForAccount.get(1);
         assertEquals(unpaidInvoice.getBalance().compareTo(BigDecimal.valueOf(249.95)), 0);
 
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentsForAccount.size(), 0);
 
         final InvoicePayment invoicePaymentRequest = new InvoicePayment();
         invoicePaymentRequest.setTargetInvoiceId(unpaidInvoice.getInvoiceId());
         invoicePaymentRequest.setAccountId(accountJson.getAccountId());
-        invoicePaymentRequest.setCurrency(unpaidInvoice.getCurrency().toString());
+        invoicePaymentRequest.setCurrency(unpaidInvoice.getCurrency());
         invoicePaymentRequest.setPurchasedAmount(unpaidInvoice.getAmount());
-        final InvoicePayment invoicePayment = killBillClient.createInvoicePayment(invoicePaymentRequest, true, requestOptions);
+        final InvoicePayment invoicePayment = invoiceApi.createInstantPayment(unpaidInvoice.getInvoiceId(), invoicePaymentRequest, true, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(invoicePayment.getPurchasedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
         assertEquals(invoicePayment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
 
@@ -158,7 +159,7 @@ public class TestExternalRefund extends TestJaxrsBase {
         invoicePaymentTransactionRequest.setPaymentId(invoicePayment.getPaymentId());
         invoicePaymentTransactionRequest.setIsAdjusted(true);
         invoicePaymentTransactionRequest.setAdjustments(unpaidInvoice.getItems());
-        final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, requestOptions);
+        final InvoicePayment invoicePaymentRefund = invoicePaymentApi.createRefundWithAdjustments(invoicePayment.getPaymentId(), invoicePaymentTransactionRequest, false, null, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentRefund);
 
         assertSingleInvoicePaymentRefund(invoicePaymentRefund);
@@ -173,16 +174,16 @@ public class TestExternalRefund extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
         // delete PM
-        killBillClient.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, requestOptions);
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        paymentMethodApi.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
 
         // external refund
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
-        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency());
         invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
-        final InvoicePayment invoicePaymentExternalRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, true, null, requestOptions);
+        final InvoicePayment invoicePaymentExternalRefund = invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), invoicePaymentTransactionRequest, true, null, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentExternalRefund);
 
         assertInvoicePaymentsExternalRefund(accountJson.getAccountId(), invoicePaymentExternalRefund);
@@ -198,22 +199,22 @@ public class TestExternalRefund extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
         // delete PM
-        killBillClient.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, requestOptions);
+        paymentMethodApi.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
 
-        final Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
         final List<InvoiceItem> itemsToBeAdjusted = invoices.get(1).getItems();
 
         // external refund
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
-        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency());
         invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
         invoicePaymentTransactionRequest.setIsAdjusted(true);
         invoicePaymentTransactionRequest.setAdjustments(itemsToBeAdjusted);
-        final InvoicePayment invoicePaymentExternalRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, true, null, requestOptions);
+        final InvoicePayment invoicePaymentExternalRefund = invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), invoicePaymentTransactionRequest, true, null, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentExternalRefund);
 
         assertInvoicePaymentsExternalRefund(accountJson.getAccountId(), invoicePaymentExternalRefund);
@@ -230,27 +231,27 @@ public class TestExternalRefund extends TestJaxrsBase {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // delete PM
-        killBillClient.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, requestOptions);
+        paymentMethodApi.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // create another PM
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
-        final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), false, PLUGIN_NAME, info);
-        final PaymentMethod otherPaymentMethod = killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
+        final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), accountJson.getAccountId(), false, PLUGIN_NAME, info, null);
+        final PaymentMethod otherPaymentMethod = accountApi.createPaymentMethod(accountJson.getAccountId(), paymentMethodJson, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
 
-        final Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
         final List<InvoiceItem> itemsToBeAdjusted = invoices.get(1).getItems();
 
         // external refund
         final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
         invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
-        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+        invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency());
         invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
         invoicePaymentTransactionRequest.setIsAdjusted(true);
         invoicePaymentTransactionRequest.setAdjustments(itemsToBeAdjusted);
-        final InvoicePayment invoicePaymentExternalRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, true, otherPaymentMethod.getPaymentMethodId(), requestOptions);
+        final InvoicePayment invoicePaymentExternalRefund = invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), invoicePaymentTransactionRequest, true, otherPaymentMethod.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNotNull(invoicePaymentExternalRefund);
         assertEquals(invoicePaymentExternalRefund.getPaymentMethodId(), otherPaymentMethod.getPaymentMethodId());
 
@@ -262,42 +263,42 @@ public class TestExternalRefund extends TestJaxrsBase {
 
     private void assertRefundInvoiceAdjustments(final UUID accountId) throws KillBillClientException {
         final Invoices invoices;
-        invoices = killBillClient.getInvoicesForAccount(accountId, true, true, requestOptions);
+        invoices = accountApi.getInvoicesForAccount(accountId, true, true, false, false, AuditLevel.NONE, requestOptions);
         final Invoice invoiceWithRefund = invoices.get(1);
         assertEquals(invoiceWithRefund.getAmount().compareTo(BigDecimal.ZERO), 0);
         assertEquals(invoiceWithRefund.getRefundAdj().compareTo(BigDecimal.valueOf(249.95).negate()), 0);
         assertEquals(invoiceWithRefund.getItems().size(), 2);
-        assertEquals(invoiceWithRefund.getItems().get(0).getItemType(), InvoiceItemType.RECURRING.toString());
+        assertEquals(invoiceWithRefund.getItems().get(0).getItemType(), InvoiceItemType.RECURRING);
         assertEquals(invoiceWithRefund.getItems().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
-        assertEquals(invoiceWithRefund.getItems().get(1).getItemType(), InvoiceItemType.ITEM_ADJ.toString());
+        assertEquals(invoiceWithRefund.getItems().get(1).getItemType(), InvoiceItemType.ITEM_ADJ);
         assertEquals(invoiceWithRefund.getItems().get(1).getAmount().compareTo(BigDecimal.valueOf(249.95).negate()), 0);
     }
 
     private void assertRefundInvoiceNoAdjustments(final UUID accountId) throws KillBillClientException {
-        final Invoices invoices = killBillClient.getInvoicesForAccount(accountId, true, true, requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountId, true, true, false, false, AuditLevel.NONE, requestOptions);
         final Invoice invoiceWithRefund = invoices.get(1);
         assertEquals(invoiceWithRefund.getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
         assertEquals(invoiceWithRefund.getRefundAdj().compareTo(BigDecimal.valueOf(249.95).negate()), 0);
         assertEquals(invoiceWithRefund.getItems().size(), 1);
-        assertEquals(invoiceWithRefund.getItems().get(0).getItemType(), InvoiceItemType.RECURRING.toString());
+        assertEquals(invoiceWithRefund.getItems().get(0).getItemType(), InvoiceItemType.RECURRING);
         assertEquals(invoiceWithRefund.getItems().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
     }
 
     private void assertRefundAccountBalance(final UUID accountId, final BigDecimal balanceAmount, final BigDecimal cbaAmount) throws KillBillClientException {
-        final Account account = killBillClient.getAccount(accountId, true, true, requestOptions);
+        final Account account = accountApi.getAccount(accountId, true, true, AuditLevel.NONE, requestOptions);
         assertEquals(account.getAccountBalance().compareTo(balanceAmount), 0);
         assertEquals(account.getAccountCBA().compareTo(cbaAmount), 0);
     }
 
     private void assertInvoicePaymentsExternalRefund(final UUID accountId, final InvoicePayment invoicePaymentExternalRefund) throws KillBillClientException {
-        final InvoicePayments invoicePaymentsForAccount = killBillClient.getInvoicePaymentsForAccount(accountId, requestOptions);
+        final InvoicePayments invoicePaymentsForAccount = accountApi.getInvoicePayments(accountId, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(invoicePaymentsForAccount.size(), 2);
 
         // INVOICE PAYMENT FOR ORIGINAL PURCHASE
         final InvoicePayment invoicePaymentPurchase = invoicePaymentsForAccount.get(0);
         assertEquals(invoicePaymentPurchase.getPurchasedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
         assertEquals(invoicePaymentPurchase.getCreditedAmount().compareTo(BigDecimal.ZERO), 0);
-        assertEquals(invoicePaymentPurchase.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE.toString());
+        assertEquals(invoicePaymentPurchase.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
         assertEquals(invoicePaymentPurchase.getTransactions().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
 
         // INVOICE PAYMENT FOR EXTERNAL REFUND
@@ -307,7 +308,7 @@ public class TestExternalRefund extends TestJaxrsBase {
         assertEquals(creditInvoicePayment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
         assertEquals(creditInvoicePayment.getCreditedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
         assertEquals(creditInvoicePayment.getTransactions().size(), 1);
-        assertEquals(creditInvoicePayment.getTransactions().get(0).getTransactionType(), TransactionType.CREDIT.toString());
+        assertEquals(creditInvoicePayment.getTransactions().get(0).getTransactionType(), TransactionType.CREDIT);
         assertEquals(creditInvoicePayment.getTransactions().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
     }
 
@@ -317,9 +318,9 @@ public class TestExternalRefund extends TestJaxrsBase {
         assertEquals(invoicePaymentRefund.getRefundedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
 
         assertEquals(invoicePaymentRefund.getTransactions().size(), 2);
-        assertEquals(invoicePaymentRefund.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE.toString());
+        assertEquals(invoicePaymentRefund.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
         assertEquals(invoicePaymentRefund.getTransactions().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
-        assertEquals(invoicePaymentRefund.getTransactions().get(1).getTransactionType(), TransactionType.REFUND.toString());
+        assertEquals(invoicePaymentRefund.getTransactions().get(1).getTransactionType(), TransactionType.REFUND);
         assertEquals(invoicePaymentRefund.getTransactions().get(1).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
     }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
index c3c279a..9c71d25 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
@@ -19,7 +19,6 @@
 package org.killbill.billing.jaxrs;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -28,18 +27,20 @@ import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.client.JaxrsResource;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.Credit;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoiceDryRun;
-import org.killbill.billing.client.model.InvoiceItem;
-import org.killbill.billing.client.model.InvoicePayment;
+import org.killbill.billing.client.model.InvoiceItems;
 import org.killbill.billing.client.model.InvoicePayments;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.PaymentMethod;
 import org.killbill.billing.client.model.Payments;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.Credit;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoiceDryRun;
+import org.killbill.billing.client.model.gen.InvoiceItem;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.PaymentMethod;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.InvoiceItemType;
@@ -51,8 +52,9 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -68,7 +70,7 @@ public class TestInvoice extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.FULL, requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.FULL, requestOptions);
         assertEquals(invoices.size(), 2);
         for (final Invoice invoiceJson : invoices) {
             Assert.assertEquals(invoiceJson.getAuditLogs().size(), 1);
@@ -92,23 +94,21 @@ public class TestInvoice extends TestJaxrsBase {
         assertEquals(invoiceItem.getPrettyPhaseName(), "shotgun-monthly-trial");
 
         // Check get with & without items
-        assertTrue(killBillClient.getInvoice(invoiceJson.getInvoiceId(), Boolean.FALSE, Boolean.FALSE, requestOptions).getItems().isEmpty());
-        assertTrue(killBillClient.getInvoice(invoiceJson.getInvoiceNumber(), Boolean.FALSE, Boolean.FALSE, requestOptions).getItems().isEmpty());
-        assertEquals(killBillClient.getInvoice(invoiceJson.getInvoiceId(), Boolean.TRUE, Boolean.FALSE, requestOptions).getItems().size(), invoiceJson.getItems().size());
-        assertEquals(killBillClient.getInvoice(invoiceJson.getInvoiceNumber(), Boolean.TRUE, Boolean.FALSE, requestOptions).getItems().size(), invoiceJson.getItems().size());
-
-
+        assertTrue(invoiceApi.getInvoice(invoiceJson.getInvoiceId(), Boolean.FALSE, Boolean.FALSE, AuditLevel.NONE, requestOptions).getItems().isEmpty());
+        assertTrue(invoiceApi.getInvoiceByNumber(Integer.valueOf(invoiceJson.getInvoiceNumber()), Boolean.FALSE, Boolean.FALSE, AuditLevel.NONE, requestOptions).getItems().isEmpty());
+        assertEquals(invoiceApi.getInvoice(invoiceJson.getInvoiceId(), Boolean.TRUE, Boolean.FALSE, AuditLevel.NONE, requestOptions).getItems().size(), invoiceJson.getItems().size());
+        assertEquals(invoiceApi.getInvoiceByNumber(Integer.valueOf(invoiceJson.getInvoiceNumber()), Boolean.TRUE, Boolean.FALSE, AuditLevel.NONE, requestOptions).getItems().size(), invoiceJson.getItems().size());
 
         // Check we can retrieve an individual invoice
-        final Invoice firstInvoice = killBillClient.getInvoice(invoiceJson.getInvoiceId(), requestOptions);
+        final Invoice firstInvoice = invoiceApi.getInvoice(invoiceJson.getInvoiceId(), true, false, AuditLevel.FULL, requestOptions);
         assertEquals(firstInvoice, invoiceJson);
 
         // Check we can retrieve the invoice by number
-        final Invoice firstInvoiceByNumberJson = killBillClient.getInvoice(invoiceJson.getInvoiceNumber(), requestOptions);
+        final Invoice firstInvoiceByNumberJson = invoiceApi.getInvoiceByNumber(Integer.valueOf(invoiceJson.getInvoiceNumber()), true, false, AuditLevel.FULL, requestOptions);
         assertEquals(firstInvoiceByNumberJson, invoiceJson);
 
         // Check we can retrieve the HTML version
-        final String htmlInvoice = killBillClient.getInvoiceAsHtml(invoiceJson.getInvoiceId(), requestOptions);
+        final String htmlInvoice = invoiceApi.getInvoiceAsHTML(invoiceJson.getInvoiceId(), requestOptions);
         assertEquals(htmlInvoice, "<html>\n" +
                                   "    <head>\n" +
                                   "        <style type=\"text/css\">\n" +
@@ -207,10 +207,9 @@ public class TestInvoice extends TestJaxrsBase {
                                   "\n");
 
         // Then create a dryRun for next upcoming invoice
-        final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.UPCOMING_INVOICE, null,
-                                                          null, null, null, null, null, null, null, null, null, null);
+        final InvoiceDryRun dryRunArg = new InvoiceDryRun().setDryRunType(DryRunType.UPCOMING_INVOICE);
 
-        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), null, dryRunArg, requestOptions);
+        final Invoice dryRunInvoice = invoiceApi.generateDryRunInvoice(dryRunArg, accountJson.getAccountId(), null, requestOptions);
         assertEquals(dryRunInvoice.getBalance(), new BigDecimal("249.95"));
         assertEquals(dryRunInvoice.getTargetDate(), new LocalDate(2012, 6, 25));
         assertEquals(dryRunInvoice.getItems().size(), 1);
@@ -220,10 +219,10 @@ public class TestInvoice extends TestJaxrsBase {
 
         final LocalDate futureDate = dryRunInvoice.getTargetDate();
         // The one more time with no DryRun
-        killBillClient.createInvoice(accountJson.getAccountId(), futureDate, requestOptions);
+        invoiceApi.createFutureInvoice(accountJson.getAccountId(), futureDate, requestOptions);
 
         // Check again # invoices, should be 3 this time
-        final List<Invoice> newInvoiceList = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> newInvoiceList = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(newInvoiceList.size(), 3);
     }
 
@@ -234,9 +233,10 @@ public class TestInvoice extends TestJaxrsBase {
 
         // "Assault-Rifle", BillingPeriod.ANNUAL, "rescue", BillingActionPolicy.IMMEDIATE,
         final Account accountJson = createAccountWithDefaultPaymentMethod();
-        final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.TARGET_DATE, SubscriptionEventType.START_BILLING,
+        final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.SUBSCRIPTION_ACTION, SubscriptionEventType.START_BILLING,
                                                           null, "Assault-Rifle", ProductCategory.BASE, BillingPeriod.ANNUAL, null, null, null, null, null, null);
-        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), new LocalDate(initialDate, DateTimeZone.forID(accountJson.getTimeZone())), dryRunArg, requestOptions);
+
+        final Invoice dryRunInvoice = invoiceApi.generateDryRunInvoice(dryRunArg, accountJson.getAccountId(), new LocalDate(initialDate, DateTimeZone.forID(accountJson.getTimeZone())), requestOptions);
         assertEquals(dryRunInvoice.getItems().size(), 1);
 
     }
@@ -247,7 +247,7 @@ public class TestInvoice extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 2);
 
         final Invoice invoiceWithPositiveAmount = Iterables.tryFind(invoices, new Predicate<Invoice>() {
@@ -258,7 +258,7 @@ public class TestInvoice extends TestJaxrsBase {
         }).orNull();
         Assert.assertNotNull(invoiceWithPositiveAmount);
 
-        final InvoicePayments objFromJson = killBillClient.getInvoicePayment(invoiceWithPositiveAmount.getInvoiceId(), requestOptions);
+        final InvoicePayments objFromJson = invoiceApi.getPaymentsForInvoice(invoiceWithPositiveAmount.getInvoiceId(), requestOptions);
         assertEquals(objFromJson.size(), 1);
         assertEquals(invoiceWithPositiveAmount.getAmount().compareTo(objFromJson.get(0).getPurchasedAmount()), 0);
     }
@@ -271,20 +271,20 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Check there was no payment made
-        assertEquals(killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions).size(), 0);
+        assertEquals(accountApi.getPaymentsForAccount(accountJson.getAccountId(), null, requestOptions).size(), 0);
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 2);
         final Invoice invoiceToPay = invoices.get(1);
         assertEquals(invoiceToPay.getBalance().compareTo(BigDecimal.ZERO), 1);
 
         // Pay all invoices
-        killBillClient.payAllInvoices(accountJson.getAccountId(), true, null, requestOptions);
-        for (final Invoice invoice : killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions)) {
+        accountApi.payAllInvoices(accountJson.getAccountId(), true, null, null, requestOptions);
+        for (final Invoice invoice : accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions)) {
             assertEquals(invoice.getBalance().compareTo(BigDecimal.ZERO), 0);
         }
-        assertEquals(killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions).size(), 1);
+        assertEquals(accountApi.getPaymentsForAccount(accountJson.getAccountId(), null, requestOptions).size(), 1);
     }
 
     @Test(groups = "slow", description = "Can create an insta-payment")
@@ -295,7 +295,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 2);
 
         for (final Invoice cur : invoices) {
@@ -308,7 +308,7 @@ public class TestInvoice extends TestJaxrsBase {
             invoicePayment.setPurchasedAmount(cur.getBalance());
             invoicePayment.setAccountId(accountJson.getAccountId());
             invoicePayment.setTargetInvoiceId(cur.getInvoiceId());
-            final InvoicePayment objFromJson = killBillClient.createInvoicePayment(invoicePayment, true, requestOptions);
+            final InvoicePayment objFromJson = invoiceApi.createInstantPayment(cur.getInvoiceId(), invoicePayment, true, null, requestOptions);
             assertEquals(cur.getBalance().compareTo(objFromJson.getPurchasedAmount()), 0);
         }
     }
@@ -318,11 +318,11 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Verify we didn't get any invoicePayment
-        final List<InvoicePayment> noPaymentsFromJson = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final List<InvoicePayment> noPaymentsFromJson = accountApi.getInvoicePayments(accountJson.getAccountId(), null, requestOptions);
         assertEquals(noPaymentsFromJson.size(), 0);
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
         final UUID invoiceId = invoices.get(1).getInvoiceId();
@@ -332,17 +332,17 @@ public class TestInvoice extends TestJaxrsBase {
         invoicePayment.setPurchasedAmount(BigDecimal.TEN);
         invoicePayment.setAccountId(accountJson.getAccountId());
         invoicePayment.setTargetInvoiceId(invoiceId);
-        killBillClient.createInvoicePayment(invoicePayment, true, requestOptions);
+        invoiceApi.createInstantPayment(invoiceId, invoicePayment, true, null, requestOptions);
 
         // Verify we indeed got the invoicePayment
-        final List<InvoicePayment> paymentsFromJson = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final List<InvoicePayment> paymentsFromJson = accountApi.getInvoicePayments(accountJson.getAccountId(), null, requestOptions);
         assertEquals(paymentsFromJson.size(), 1);
         assertEquals(paymentsFromJson.get(0).getPurchasedAmount().compareTo(BigDecimal.TEN), 0);
         assertEquals(paymentsFromJson.get(0).getTargetInvoiceId(), invoiceId);
 
         // Check the PaymentMethod from paymentMethodId returned in the Payment object
         final UUID paymentMethodId = paymentsFromJson.get(0).getPaymentMethodId();
-        final PaymentMethod paymentMethodJson = killBillClient.getPaymentMethod(paymentMethodId, requestOptions);
+        final PaymentMethod paymentMethodJson = paymentMethodApi.getPaymentMethod(paymentMethodId, null, requestOptions);
         assertEquals(paymentMethodJson.getPaymentMethodId(), paymentMethodId);
         assertEquals(paymentMethodJson.getAccountId(), accountJson.getAccountId());
         assertEquals(paymentMethodJson.getPluginName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
@@ -354,7 +354,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
         final Invoice invoice = invoices.get(1);
@@ -374,16 +374,16 @@ public class TestInvoice extends TestJaxrsBase {
                                    "  \"reason\": \"SLA not met\"\n" +
                                    "}";
         adjustmentInvoiceItem.setItemDetails(itemDetails);
-        killBillClient.adjustInvoiceItem(adjustmentInvoiceItem, requestOptions);
+        invoiceApi.adjustInvoiceItem(invoice.getInvoiceId(), adjustmentInvoiceItem, null, requestOptions);
 
         // Verify the new invoice balance is zero
-        final Invoice adjustedInvoice = killBillClient.getInvoice(invoice.getInvoiceId(), true, false, AuditLevel.FULL, requestOptions);
+        final Invoice adjustedInvoice = invoiceApi.getInvoice(invoice.getInvoiceId(), true, false, AuditLevel.FULL, requestOptions);
         assertEquals(adjustedInvoice.getAmount().compareTo(BigDecimal.ZERO), 0);
 
         final InvoiceItem createdAdjustment = Iterables.find(adjustedInvoice.getItems(), new Predicate<InvoiceItem>() {
             @Override
             public boolean apply(final InvoiceItem input) {
-                return InvoiceItemType.ITEM_ADJ.toString().equals(input.getItemType());
+                return InvoiceItemType.ITEM_ADJ.equals(input.getItemType());
             }
         });
         assertEquals(createdAdjustment.getItemDetails(), itemDetails);
@@ -428,7 +428,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
         final Invoice invoice = invoices.get(1);
@@ -445,11 +445,11 @@ public class TestInvoice extends TestJaxrsBase {
         adjustmentInvoiceItem.setInvoiceId(invoice.getInvoiceId());
         adjustmentInvoiceItem.setInvoiceItemId(invoiceItem.getInvoiceItemId());
         adjustmentInvoiceItem.setAmount(adjustedAmount);
-        adjustmentInvoiceItem.setCurrency(invoice.getCurrency().name());
-        killBillClient.adjustInvoiceItem(adjustmentInvoiceItem, requestOptions);
+        adjustmentInvoiceItem.setCurrency(invoice.getCurrency());
+        invoiceApi.adjustInvoiceItem(invoice.getInvoiceId(), adjustmentInvoiceItem, null, requestOptions);
 
         // Verify the new invoice balance
-        final Invoice adjustedInvoice = killBillClient.getInvoice(invoice.getInvoiceId(), requestOptions);
+        final Invoice adjustedInvoice = invoiceApi.getInvoice(invoice.getInvoiceId(), requestOptions);
         final BigDecimal adjustedInvoiceBalance = invoice.getBalance().add(adjustedAmount.negate()).setScale(2, BigDecimal.ROUND_HALF_UP);
         assertEquals(adjustedInvoice.getBalance().compareTo(adjustedInvoiceBalance), 0, String.format("Adjusted invoice balance is %s, should be %s", adjustedInvoice.getBalance(), adjustedInvoiceBalance));
     }
@@ -459,7 +459,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final Invoices originalInvoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices originalInvoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(originalInvoices.size(), 2);
 
         final UUID firstInvoiceItemId = originalInvoices.get(0).getItems().get(0).getInvoiceItemId();
@@ -479,9 +479,12 @@ public class TestInvoice extends TestJaxrsBase {
         final LocalDate endDate = startDate.plusDays(10);
         externalCharge.setEndDate(endDate);
 
-        final List<InvoiceItem> createdExternalCharges = killBillClient.createExternalCharges(ImmutableList.of(externalCharge), clock.getUTCToday(), false, true, requestOptions);
+        final InvoiceItems itemsForCharge = new InvoiceItems();
+        itemsForCharge.add(externalCharge);
+
+        final List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountJson.getAccountId(), itemsForCharge, clock.getUTCToday(), false, null, true, null, null, requestOptions);
         assertEquals(createdExternalCharges.size(), 1);
-        final Invoice invoiceWithItems = killBillClient.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true, false, requestOptions);
+        final Invoice invoiceWithItems = invoiceApi.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoiceWithItems.getBalance().compareTo(chargeAmount), 0);
         assertEquals(invoiceWithItems.getItems().size(), 1);
         assertEquals(invoiceWithItems.getItems().get(0).getDescription(), externalCharge.getDescription());
@@ -492,7 +495,7 @@ public class TestInvoice extends TestJaxrsBase {
         assertEquals(invoiceWithItems.getItems().get(0).getLinkedInvoiceItemId(), firstInvoiceItemId);
 
         // Verify the total number of invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
     }
 
     @Test(groups = "slow", description = "Can create multiple external charges")
@@ -500,12 +503,12 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 2);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions).size(), 2);
 
         // Post an external charge
         final BigDecimal chargeAmount = BigDecimal.TEN;
 
-        final List<InvoiceItem> externalCharges = new ArrayList<InvoiceItem>();
+        final InvoiceItems externalCharges = new InvoiceItems();
 
         // Does not pass currency to test on purpose that we will default to account currency
         final InvoiceItem externalCharge1 = new InvoiceItem();
@@ -521,13 +524,13 @@ public class TestInvoice extends TestJaxrsBase {
         externalCharge2.setDescription(UUID.randomUUID().toString());
         externalCharges.add(externalCharge2);
 
-        final List<InvoiceItem> createdExternalCharges = killBillClient.createExternalCharges(externalCharges, clock.getUTCToday(), false, true, requestOptions);
+        final List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountJson.getAccountId(), externalCharges, clock.getUTCToday(), false, null, true, null, null, requestOptions);
         assertEquals(createdExternalCharges.size(), 2);
         assertEquals(createdExternalCharges.get(0).getCurrency(), accountJson.getCurrency());
         assertEquals(createdExternalCharges.get(1).getCurrency(), accountJson.getCurrency());
 
         // Verify the total number of invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
     }
 
     @Test(groups = "slow", description = "Can create multiple external charges with same invoice and external keys")
@@ -535,12 +538,12 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 2);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions).size(), 2);
 
         // Post an external charge
         final BigDecimal chargeAmount = BigDecimal.TEN;
 
-        final List<InvoiceItem> externalCharges = new ArrayList<InvoiceItem>();
+        final InvoiceItems externalCharges = new InvoiceItems();
 
         // Does not pass currency to test on purpose that we will default to account currency
         final InvoiceItem externalCharge1 = new InvoiceItem();
@@ -559,17 +562,15 @@ public class TestInvoice extends TestJaxrsBase {
         final String paymentExternalKey = "anyPaymentExternalKey";
         final String transactionExternalKey = "anyTransactionExternalKey";
 
-        final List<InvoiceItem> createdExternalCharges =
-                killBillClient.createExternalCharges(externalCharges, clock.getUTCToday(), true, true,
-                                                     paymentExternalKey, transactionExternalKey, requestOptions);
+        final List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountJson.getAccountId(), externalCharges, clock.getUTCToday(), true, null, true, paymentExternalKey, transactionExternalKey, requestOptions);
         assertEquals(createdExternalCharges.size(), 2);
         assertEquals(createdExternalCharges.get(0).getCurrency(), accountJson.getCurrency());
         assertEquals(createdExternalCharges.get(1).getCurrency(), accountJson.getCurrency());
 
         // Verify the total number of invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
 
-        final Payments payments = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), AuditLevel.NONE, requestOptions);
+        final Payments payments = accountApi.getPaymentsForAccount(accountJson.getAccountId(), null, requestOptions);
         assertNotNull(payments);
         // Verify payment with paymentExternalKey provided
         assertEquals(payments.get(payments.size() - 1).getPaymentExternalKey(), paymentExternalKey);
@@ -582,7 +583,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 2);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions).size(), 2);
 
         // Post an external charge
         final BigDecimal chargeAmount = BigDecimal.TEN;
@@ -590,15 +591,18 @@ public class TestInvoice extends TestJaxrsBase {
         externalCharge.setAccountId(accountJson.getAccountId());
         externalCharge.setAmount(chargeAmount);
         externalCharge.setCurrency(accountJson.getCurrency());
-        final List<InvoiceItem> createdExternalCharges = killBillClient.createExternalCharges(ImmutableList.<InvoiceItem>of(externalCharge), clock.getUTCToday(), true, true, requestOptions);
+        final InvoiceItems inputExternalCharges = new InvoiceItems();
+        inputExternalCharges.add(externalCharge);
+
+        final List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountJson.getAccountId(), inputExternalCharges, clock.getUTCToday(), true, null, true, null, null, requestOptions);
         assertEquals(createdExternalCharges.size(), 1);
-        final Invoice invoiceWithItems = killBillClient.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true);
+        final Invoice invoiceWithItems = invoiceApi.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoiceWithItems.getBalance().compareTo(BigDecimal.ZERO), 0);
         assertEquals(invoiceWithItems.getItems().size(), 1);
         assertNull(invoiceWithItems.getItems().get(0).getBundleId());
 
         // Verify the total number of invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
     }
 
     @Test(groups = "slow", description = "Can create an external charge for a bundle")
@@ -606,7 +610,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 2);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions).size(), 2);
 
         // Post an external charge
         final BigDecimal chargeAmount = BigDecimal.TEN;
@@ -616,15 +620,17 @@ public class TestInvoice extends TestJaxrsBase {
         externalCharge.setAmount(chargeAmount);
         externalCharge.setCurrency(accountJson.getCurrency());
         externalCharge.setBundleId(bundleId);
-        final List<InvoiceItem> createdExternalCharges = killBillClient.createExternalCharges(ImmutableList.<InvoiceItem>of(externalCharge), clock.getUTCToday(), false, true, requestOptions);
+        final InvoiceItems input = new InvoiceItems();
+        input.add(externalCharge);
+        final List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountJson.getAccountId(), input, clock.getUTCToday(), false, null, true, null, null, requestOptions);
         assertEquals(createdExternalCharges.size(), 1);
-        final Invoice invoiceWithItems = killBillClient.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true);
+        final Invoice invoiceWithItems = invoiceApi.getInvoice(createdExternalCharges.get(0).getInvoiceId(), true, null, AuditLevel.NONE, requestOptions);
         assertEquals(invoiceWithItems.getBalance().compareTo(chargeAmount), 0);
         assertEquals(invoiceWithItems.getItems().size(), 1);
         assertEquals(invoiceWithItems.getItems().get(0).getBundleId(), bundleId);
 
         // Verify the total number of invoices
-        assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
+        assertEquals(accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
     }
 
     @Test(groups = "slow", description = "Can paginate and search through all invoices")
@@ -637,17 +643,17 @@ public class TestInvoice extends TestJaxrsBase {
             callbackServlet.assertListenerStatus();
         }
 
-        final Invoices allInvoices = killBillClient.getInvoices(requestOptions);
+        final Invoices allInvoices = invoiceApi.getInvoices(requestOptions);
         Assert.assertEquals(allInvoices.size(), 5);
 
         for (final Invoice invoice : allInvoices) {
-            Assert.assertEquals(killBillClient.searchInvoices(invoice.getInvoiceId().toString(), requestOptions).size(), 1);
-            Assert.assertEquals(killBillClient.searchInvoices(invoice.getAccountId().toString(), requestOptions).size(), 5);
-            Assert.assertEquals(killBillClient.searchInvoices(invoice.getInvoiceNumber().toString(), requestOptions).size(), 1);
-            Assert.assertEquals(killBillClient.searchInvoices(invoice.getCurrency().toString(), requestOptions).size(), 5);
+            Assert.assertEquals(invoiceApi.searchInvoices(invoice.getInvoiceId().toString(), requestOptions).size(), 1);
+            Assert.assertEquals(invoiceApi.searchInvoices(invoice.getAccountId().toString(), requestOptions).size(), 5);
+            Assert.assertEquals(invoiceApi.searchInvoices(invoice.getInvoiceNumber().toString(), requestOptions).size(), 1);
+            Assert.assertEquals(invoiceApi.searchInvoices(invoice.getCurrency().toString(), requestOptions).size(), 5);
         }
 
-        Invoices page = killBillClient.getInvoices(0L, 1L, requestOptions);
+        Invoices page = invoiceApi.getInvoices(0L, 1L, false, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
@@ -667,15 +673,15 @@ public class TestInvoice extends TestJaxrsBase {
         credit.setAccountId(account.getAccountId());
         credit.setInvoiceId(null);
         credit.setCreditAmount(creditAmount);
-        final Credit creditJson = killBillClient.createCredit(credit, false, requestOptions);
+        final Credit creditJson = creditApi.createCredit(credit, false, requestOptions);
 
-        Invoice invoice = killBillClient.getInvoice(creditJson.getInvoiceId());
-        Assert.assertEquals(invoice.getStatus(), InvoiceStatus.DRAFT.toString());
+        Invoice invoice = invoiceApi.getInvoice(creditJson.getInvoiceId(), requestOptions);
+        Assert.assertEquals(invoice.getStatus(), InvoiceStatus.DRAFT);
 
-        killBillClient.commitInvoice(invoice.getInvoiceId(), requestOptions);
+        invoiceApi.commitInvoice(invoice.getInvoiceId(), requestOptions);
 
-        invoice = killBillClient.getInvoice(creditJson.getInvoiceId(), requestOptions);
-        Assert.assertEquals(invoice.getStatus(), InvoiceStatus.COMMITTED.toString());
+        invoice = invoiceApi.getInvoice(creditJson.getInvoiceId(), requestOptions);
+        Assert.assertEquals(invoice.getStatus(), InvoiceStatus.COMMITTED);
     }
 
     @Test(groups = "slow", description = "Can create a migration invoice")
@@ -683,7 +689,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoices.size(), 2);
 
         // Migrate an invoice with one external charge
@@ -692,21 +698,25 @@ public class TestInvoice extends TestJaxrsBase {
         externalCharge.setStartDate(new LocalDate());
         externalCharge.setAccountId(accountJson.getAccountId());
         externalCharge.setAmount(chargeAmount);
-        externalCharge.setItemType(InvoiceItemType.EXTERNAL_CHARGE.toString());
+        externalCharge.setItemType(InvoiceItemType.EXTERNAL_CHARGE);
         externalCharge.setCurrency(accountJson.getCurrency());
+        final InvoiceItems inputInvoice = new InvoiceItems();
+        inputInvoice.add(externalCharge);
+        final Account accountWithBalance = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
 
-        final Account accountWithBalance = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final Multimap<String, String> queryFollowParams = HashMultimap.<String, String>create(requestOptions.getQueryParamsForFollow());
+        queryFollowParams.put(JaxrsResource.QUERY_INVOICE_WITH_ITEMS, "true");
 
-        final Invoice migrationInvoice = killBillClient.createMigrationInvoice(accountJson.getAccountId(), null, ImmutableList.<InvoiceItem>of(externalCharge), requestOptions);
+        final Invoice migrationInvoice = invoiceApi.createMigrationInvoice(accountJson.getAccountId(), inputInvoice, null, requestOptions.extend().withQueryParamsForFollow(queryFollowParams).build());
         assertEquals(migrationInvoice.getBalance(), BigDecimal.ZERO);
         assertEquals(migrationInvoice.getItems().size(), 1);
         assertEquals(migrationInvoice.getItems().get(0).getAmount().compareTo(chargeAmount), 0);
         assertEquals(migrationInvoice.getItems().get(0).getCurrency(), accountJson.getCurrency());
 
-        final List<Invoice> invoicesWithMigration = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final List<Invoice> invoicesWithMigration = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, true, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(invoicesWithMigration.size(), 3);
 
-        final Account accountWithBalanceAfterMigration = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        final Account accountWithBalanceAfterMigration = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(accountWithBalanceAfterMigration.getAccountBalance().compareTo(accountWithBalance.getAccountBalance()), 0);
     }
 
@@ -722,23 +732,23 @@ public class TestInvoice extends TestJaxrsBase {
         credit.setCreditAmount(creditAmount);
 
         // insert credit to child account
-        final Credit creditJson = killBillClient.createCredit(credit, true, requestOptions);
+        final Credit creditJson = creditApi.createCredit(credit, true, requestOptions);
 
-        Invoices childInvoices = killBillClient.getInvoicesForAccount(childAccount.getAccountId(), true, false, requestOptions);
+        Invoices childInvoices = accountApi.getInvoicesForAccount(childAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(childInvoices.size(), 1);
         Assert.assertEquals(childInvoices.get(0).getCreditAdj().compareTo(BigDecimal.TEN), 0);
 
-        Invoices parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        Invoices parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(parentInvoices.size(), 0);
 
         // transfer credit to parent account
-        killBillClient.transferChildCreditToParent(childAccount.getAccountId(), requestOptions);
+        accountApi.transferChildCreditToParent(childAccount.getAccountId(), requestOptions);
 
-        childInvoices = killBillClient.getInvoicesForAccount(childAccount.getAccountId(), true, false, requestOptions);
+        childInvoices = accountApi.getInvoicesForAccount(childAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(childInvoices.size(), 2);
         Assert.assertEquals(childInvoices.get(1).getCreditAdj().compareTo(BigDecimal.TEN.negate()), 0);
 
-        parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(parentInvoices.size(), 1);
         Assert.assertEquals(parentInvoices.get(0).getCreditAdj().compareTo(BigDecimal.TEN), 0);
     }
@@ -749,7 +759,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account account = createAccount();
 
         // transfer credit to parent account
-        killBillClient.transferChildCreditToParent(account.getAccountId(), requestOptions);
+        accountApi.transferChildCreditToParent(account.getAccountId(), requestOptions);
 
     }
 
@@ -760,7 +770,7 @@ public class TestInvoice extends TestJaxrsBase {
         final Account childAccount = createAccount(parentAccount.getAccountId());
 
         // transfer credit to parent account
-        killBillClient.transferChildCreditToParent(childAccount.getAccountId(), requestOptions);
+        accountApi.transferChildCreditToParent(childAccount.getAccountId(), requestOptions);
 
     }
 
@@ -775,12 +785,12 @@ public class TestInvoice extends TestJaxrsBase {
         final Account childAccount3 = createAccount(parentAccount.getAccountId());
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        createEntitlement(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
-                          ProductCategory.BASE, BillingPeriod.MONTHLY, true);
-        createEntitlement(childAccount2.getAccountId(), UUID.randomUUID().toString(), "Pistol",
-                          ProductCategory.BASE, BillingPeriod.MONTHLY, true);
-        createEntitlement(childAccount3.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
-                          ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+                           ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(childAccount2.getAccountId(), UUID.randomUUID().toString(), "Pistol",
+                           ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(childAccount3.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+                           ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE,
                                            ExtBusEventType.SUBSCRIPTION_PHASE,
@@ -792,9 +802,9 @@ public class TestInvoice extends TestJaxrsBase {
         clock.addDays(32);
         callbackServlet.assertListenerStatus();
 
-        final List<Invoice> child1Invoices = killBillClient.getInvoicesForAccount(childAccount1.getAccountId(), true, false, requestOptions);
-        final List<Invoice> child2Invoices = killBillClient.getInvoicesForAccount(childAccount2.getAccountId(), true, false, requestOptions);
-        final List<Invoice> child3Invoices = killBillClient.getInvoicesForAccount(childAccount3.getAccountId(), true, false, requestOptions);
+        final List<Invoice> child1Invoices = accountApi.getInvoicesForAccount(childAccount1.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
+        final List<Invoice> child2Invoices = accountApi.getInvoicesForAccount(childAccount2.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
+        final List<Invoice> child3Invoices = accountApi.getInvoicesForAccount(childAccount3.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
 
         assertEquals(child1Invoices.size(), 2);
         final Invoice child1RecurringInvoice = child1Invoices.get(1);
@@ -802,12 +812,12 @@ public class TestInvoice extends TestJaxrsBase {
         final InvoiceItem child2RecurringInvoiceItem = child2Invoices.get(1).getItems().get(0);
         final InvoiceItem child3RecurringInvoiceItem = child3Invoices.get(1).getItems().get(0);
 
-        final List<Invoice> parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        final List<Invoice> parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoices.size(), 2);
 
         // check parent invoice with child invoice items and no adjustments
         // parameters: withItems = true, withChildrenItems = true
-        Invoice parentInvoiceWithChildItems = killBillClient.getInvoice(parentInvoices.get(1).getInvoiceId(), true, true, requestOptions);
+        Invoice parentInvoiceWithChildItems = invoiceApi.getInvoice(parentInvoices.get(1).getInvoiceId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoiceWithChildItems.getItems().size(), 3);
         assertEquals(parentInvoiceWithChildItems.getItems().get(0).getChildItems().size(), 1);
         assertEquals(parentInvoiceWithChildItems.getItems().get(1).getChildItems().size(), 1);
@@ -820,12 +830,12 @@ public class TestInvoice extends TestJaxrsBase {
         adjustmentInvoiceItem.setInvoiceItemId(child1RecurringInvoiceItem.getInvoiceItemId());
         adjustmentInvoiceItem.setAmount(BigDecimal.TEN);
         adjustmentInvoiceItem.setCurrency(child1RecurringInvoiceItem.getCurrency());
-        final Invoice invoiceAdjustment = killBillClient.adjustInvoiceItem(adjustmentInvoiceItem, requestOptions);
-        final InvoiceItem child1AdjInvoiceItem = killBillClient.getInvoice(invoiceAdjustment.getInvoiceId(), requestOptions).getItems().get(1);
+        final Invoice invoiceAdjustment = invoiceApi.adjustInvoiceItem(child1RecurringInvoice.getInvoiceId(), adjustmentInvoiceItem, null, requestOptions);
+        final InvoiceItem child1AdjInvoiceItem = invoiceApi.getInvoice(invoiceAdjustment.getInvoiceId(), true, true, AuditLevel.NONE, requestOptions).getItems().get(1);
 
         // check parent invoice with child invoice items and adjustments
         // parameters: withItems = true, withChildrenItems = true
-        parentInvoiceWithChildItems = killBillClient.getInvoice(parentInvoices.get(1).getInvoiceId(), true, true, requestOptions);
+        parentInvoiceWithChildItems = invoiceApi.getInvoice(parentInvoices.get(1).getInvoiceId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoiceWithChildItems.getItems().size(), 3);
         assertEquals(parentInvoiceWithChildItems.getItems().get(0).getChildItems().size(), 2);
         assertEquals(parentInvoiceWithChildItems.getItems().get(1).getChildItems().size(), 1);
@@ -843,7 +853,7 @@ public class TestInvoice extends TestJaxrsBase {
         assertTrue(child3InvoiceItemFromParent.equals(child3RecurringInvoiceItem));
 
         // check parent invoice without child invoice items
-        parentInvoiceWithChildItems = killBillClient.getInvoice(parentInvoices.get(1).getInvoiceId(), true, false, requestOptions);
+        parentInvoiceWithChildItems = invoiceApi.getInvoice(parentInvoices.get(1).getInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoiceWithChildItems.getItems().size(), 3);
         assertNull(parentInvoiceWithChildItems.getItems().get(0).getChildItems());
         assertNull(parentInvoiceWithChildItems.getItems().get(1).getChildItems());
@@ -851,7 +861,7 @@ public class TestInvoice extends TestJaxrsBase {
 
         // check parent invoice without items but with child invoice items and adjustment. Should return items anyway.
         // parameters: withItems = false, withChildrenItems = true
-        parentInvoiceWithChildItems = killBillClient.getInvoice(parentInvoices.get(1).getInvoiceId(), false, true, requestOptions);
+        parentInvoiceWithChildItems = invoiceApi.getInvoice(parentInvoices.get(1).getInvoiceId(), false, true, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoiceWithChildItems.getItems().size(), 3);
         assertEquals(parentInvoiceWithChildItems.getItems().get(0).getChildItems().size(), 2);
         assertEquals(parentInvoiceWithChildItems.getItems().get(1).getChildItems().size(), 1);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceItem.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceItem.java
index a846d1b..449847b 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceItem.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceItem.java
@@ -17,20 +17,19 @@
 
 package org.killbill.billing.jaxrs;
 
-import java.util.Collection;
-import java.util.LinkedList;
 import java.util.List;
+import java.util.UUID;
 
-import org.killbill.billing.GuicyKillbillTestSuite;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.CustomField;
-import org.killbill.billing.client.model.InvoiceItem;
+import org.killbill.billing.client.model.CustomFields;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.Tag;
-import org.killbill.billing.client.model.TagDefinition;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.CustomField;
+import org.killbill.billing.client.model.gen.InvoiceItem;
+import org.killbill.billing.client.model.gen.Tag;
+import org.killbill.billing.client.model.gen.TagDefinition;
 import org.killbill.billing.jaxrs.resources.JaxrsResource;
 import org.killbill.billing.util.api.AuditLevel;
 import org.testng.Assert;
@@ -45,7 +44,7 @@ public class TestInvoiceItem extends TestJaxrsBase {
     @Test(groups = "slow", description = "Add tags to invoice item")
     public void testTags() throws Exception {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final Invoices invoicesJson = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoicesJson = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
 
         Assert.assertNotNull(invoicesJson);
         Assert.assertEquals(invoicesJson.size(), 2);
@@ -55,9 +54,9 @@ public class TestInvoiceItem extends TestJaxrsBase {
         Assert.assertNotNull(invoiceItems);
 
         // Create tag definition
-        final TagDefinition input = new TagDefinition(null, false, "tagtest", "invoice item tag test", ImmutableList.<ObjectType>of(ObjectType.INVOICE_ITEM));
+        final TagDefinition input = new TagDefinition(null, false, "tagtest", "invoice item tag test", ImmutableList.<ObjectType>of(ObjectType.INVOICE_ITEM), null);
 
-        final TagDefinition objFromJson = killBillClient.createTagDefinition(input, requestOptions);
+        final TagDefinition objFromJson = tagDefinitionApi.createTagDefinition(input, requestOptions);
         Assert.assertNotNull(objFromJson);
         Assert.assertEquals(objFromJson.getName(), input.getName());
         Assert.assertEquals(objFromJson.getDescription(), input.getDescription());
@@ -66,23 +65,18 @@ public class TestInvoiceItem extends TestJaxrsBase {
         final Multimap<String, String> followQueryParams = HashMultimap.create();
         followQueryParams.put(JaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAccountId().toString());
         final RequestOptions followRequestOptions = requestOptions.extend().withQueryParamsForFollow(followQueryParams).build();
-        killBillClient.createInvoiceItemTag(invoiceItems.get(0).getInvoiceItemId(),objFromJson.getId(), followRequestOptions);
+        invoiceItemApi.createInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), ImmutableList.<UUID>of(objFromJson.getId()), followRequestOptions);
 
-        // Add account id to request
-        final Multimap<String, String> queryParams = HashMultimap.create();
-        queryParams.put(JaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAccountId().toString());
-        final RequestOptions addedRequestOptions = requestOptions.extend().withQueryParams(queryParams).build();
-        
         // Retrieves all tags
-        final List<Tag> tags1 = killBillClient.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), AuditLevel.FULL, addedRequestOptions);
+        final List<Tag> tags1 = invoiceItemApi.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), accountJson.getAccountId(), null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(tags1.size(), 1);
         Assert.assertEquals(tags1.get(0).getTagDefinitionId(), objFromJson.getId());
 
         // Verify adding the same tag a second time doesn't do anything
-        killBillClient.createInvoiceItemTag(invoiceItems.get(0).getInvoiceItemId(), objFromJson.getId(), followRequestOptions);
+        invoiceItemApi.createInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), ImmutableList.<UUID>of(objFromJson.getId()), followRequestOptions);
 
         // Retrieves all tags again
-        final List<Tag> tags2 = killBillClient.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), AuditLevel.FULL, addedRequestOptions);
+        final List<Tag> tags2 = invoiceItemApi.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), accountJson.getAccountId(), null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(tags2, tags1);
 
         // Verify audit logs
@@ -96,15 +90,15 @@ public class TestInvoiceItem extends TestJaxrsBase {
         Assert.assertNotNull(auditLogJson.getUserToken());
 
         // remove it
-        killBillClient.deleteInvoiceItemTag(invoiceItems.get(0).getInvoiceItemId(), objFromJson.getId(), requestOptions);
-        final List<Tag> tags3 = killBillClient.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), AuditLevel.FULL, addedRequestOptions);
+        invoiceItemApi.deleteInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), ImmutableList.<UUID>of(objFromJson.getId()), requestOptions);
+        final List<Tag> tags3 = invoiceItemApi.getInvoiceItemTags(invoiceItems.get(0).getInvoiceItemId(), accountJson.getAccountId(), null, AuditLevel.FULL, requestOptions);
         Assert.assertEquals(tags3.size(), 0);
 
-        killBillClient.deleteTagDefinition(objFromJson.getId(),requestOptions);
-        List<TagDefinition> objsFromJson = killBillClient.getTagDefinitions(requestOptions);
+        tagDefinitionApi.deleteTagDefinition(objFromJson.getId(), requestOptions);
+        List<TagDefinition> objsFromJson = tagDefinitionApi.getTagDefinitions(requestOptions);
         Assert.assertNotNull(objsFromJson);
         Boolean isFound = false;
-        for (TagDefinition tagDefinition : objsFromJson){
+        for (TagDefinition tagDefinition : objsFromJson) {
             isFound |= tagDefinition.getId().equals(objFromJson.getId());
         }
         Assert.assertFalse(isFound);
@@ -113,7 +107,7 @@ public class TestInvoiceItem extends TestJaxrsBase {
     @Test(groups = "slow", description = "Add custom fields to invoice item")
     public void testCustomFields() throws Exception {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final Invoices invoicesJson = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoicesJson = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
 
         Assert.assertNotNull(invoicesJson);
         Assert.assertEquals(invoicesJson.size(), 2);
@@ -122,20 +116,20 @@ public class TestInvoiceItem extends TestJaxrsBase {
 
         Assert.assertNotNull(invoiceItems);
 
-        final Collection<CustomField> customFields = new LinkedList<CustomField>();
+        final CustomFields customFields = new CustomFields();
         customFields.add(new CustomField(null, invoiceItems.get(0).getInvoiceItemId(), ObjectType.INVOICE_ITEM, "1", "value1", null));
         customFields.add(new CustomField(null, invoiceItems.get(0).getInvoiceItemId(), ObjectType.INVOICE_ITEM, "2", "value2", null));
         customFields.add(new CustomField(null, invoiceItems.get(0).getInvoiceItemId(), ObjectType.INVOICE_ITEM, "3", "value3", null));
 
-        killBillClient.createInvoiceItemCustomField(invoiceItems.get(0).getInvoiceItemId(), customFields, requestOptions);
+        invoiceItemApi.createInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), customFields, requestOptions);
 
-        final List<CustomField> invoiceItemCustomFields = killBillClient.getInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), requestOptions);
+        final List<CustomField> invoiceItemCustomFields = invoiceItemApi.getInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), requestOptions);
         Assert.assertEquals(invoiceItemCustomFields.size(), 3);
 
         // Delete all custom fields for account
-        killBillClient.deleteInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), requestOptions);
+        invoiceItemApi.deleteInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), null, requestOptions);
 
-        final List<CustomField> remainingCustomFields = killBillClient.getInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), requestOptions);
+        final List<CustomField> remainingCustomFields = invoiceItemApi.getInvoiceItemCustomFields(invoiceItems.get(0).getInvoiceItemId(), requestOptions);
         Assert.assertEquals(remainingCustomFields.size(), 0);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
index c382e30..a3f4af8 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
@@ -27,30 +27,31 @@ import org.joda.time.DateTime;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoiceItem;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
 import org.killbill.billing.client.model.InvoicePayments;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentTransaction;
 import org.killbill.billing.client.model.Payments;
-import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoiceItem;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.Subscription;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
+import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
 
 import static org.testng.Assert.assertEquals;
@@ -75,38 +76,35 @@ public class TestInvoicePayment extends TestJaxrsBase {
         mockPaymentProviderPlugin = (MockPaymentProviderPlugin) registry.getServiceForName(PLUGIN_NAME);
     }
 
-
-
-
     @Test(groups = "slow")
     public void testRetrievePayment() throws Exception {
         final InvoicePayment paymentJson = setupScenarioWithPayment(true);
-        final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), false, requestOptions);
-        Assert.assertTrue(retrievedPaymentJson.equals((Payment) paymentJson));
+        final Payment retrievedPaymentJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyInvoicePaymentAgainstPayment(paymentJson, retrievedPaymentJson);
     }
 
-
     @Test(groups = "slow")
     public void testInvoicePaymentCompletion() throws Exception {
         mockPaymentProviderPlugin.makeNextPaymentPending();
 
         final InvoicePayment paymentJson = setupScenarioWithPayment(false);
 
-        final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), false, requestOptions);
-        Assert.assertTrue(retrievedPaymentJson.equals((Payment) paymentJson));
+        final Payment retrievedPaymentJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyInvoicePaymentAgainstPayment(paymentJson, retrievedPaymentJson);
         Assert.assertEquals(retrievedPaymentJson.getTransactions().size(), 1);
-        Assert.assertEquals(retrievedPaymentJson.getTransactions().get(0).getStatus(), "PENDING");
+        Assert.assertEquals(retrievedPaymentJson.getTransactions().get(0).getStatus(), TransactionStatus.PENDING);
 
         final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
         completeTransactionByPaymentId.setPaymentId(retrievedPaymentJson.getPaymentId());
 
-        final Account accountWithBalance = killBillClient.getAccount(paymentJson.getAccountId(), true, false, requestOptions);
+        final Account accountWithBalance = accountApi.getAccount(paymentJson.getAccountId(), true, false, AuditLevel.NONE, requestOptions);
         Assert.assertTrue(accountWithBalance.getAccountBalance().compareTo(BigDecimal.ZERO) > 0);
 
-        final Payment completedPayment = killBillClient.completeInvoicePayment(completeTransactionByPaymentId, null, ImmutableMap.<String, String>of(), requestOptions);
-        Assert.assertEquals(completedPayment.getTransactions().get(0).getStatus(), "SUCCESS");
+        invoicePaymentApi.completeInvoicePaymentTransaction(retrievedPaymentJson.getPaymentId(), new PaymentTransaction(), NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment completedPayment = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        Assert.assertEquals(completedPayment.getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS);
 
-        final Account accountWithBalance2 = killBillClient.getAccount(paymentJson.getAccountId(), true, false, requestOptions);
+        final Account accountWithBalance2 = accountApi.getAccount(paymentJson.getAccountId(), true, false, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(accountWithBalance2.getAccountBalance().compareTo(BigDecimal.ZERO), 0);
 
     }
@@ -123,7 +121,8 @@ public class TestInvoicePayment extends TestJaxrsBase {
         final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
         refund.setPaymentId(invoicePaymentJson.getPaymentId());
         refund.setAmount(refundAmount);
-        final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+        invoicePaymentApi.createRefundWithAdjustments(invoicePaymentJson.getPaymentId(), refund, invoicePaymentJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment paymentAfterRefundJson = paymentApi.getPayment(invoicePaymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyRefund(invoicePaymentJson, paymentAfterRefundJson, refundAmount);
 
         // Verify the invoice balance
@@ -142,7 +141,9 @@ public class TestInvoicePayment extends TestJaxrsBase {
         final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
         refund.setPaymentId(paymentJson.getPaymentId());
         refund.setAmount(refundAmount);
-        final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+
+        invoicePaymentApi.createRefundWithAdjustments(paymentJson.getPaymentId(), refund, paymentJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment paymentAfterRefundJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
 
         // Verify the invoice balance
@@ -154,7 +155,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
         final InvoicePayment paymentJson = setupScenarioWithPayment(true);
 
         // Get the individual items for the invoice
-        final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true, false, requestOptions);
+        final Invoice invoice = invoiceApi.getInvoice(paymentJson.getTargetInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         final InvoiceItem itemToAdjust = invoice.getItems().get(0);
 
         // Issue a refund for the full amount
@@ -168,9 +169,11 @@ public class TestInvoicePayment extends TestJaxrsBase {
         refund.setIsAdjusted(true);
         final InvoiceItem adjustment = new InvoiceItem();
         adjustment.setInvoiceItemId(itemToAdjust.getInvoiceItemId());
-        /* null amount means full adjustment for that item */
+        //null amount means full adjustment for that item
         refund.setAdjustments(ImmutableList.<InvoiceItem>of(adjustment));
-        final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+
+        invoicePaymentApi.createRefundWithAdjustments(paymentJson.getPaymentId(), refund, paymentJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment paymentAfterRefundJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
 
         // Verify the invoice balance
@@ -182,7 +185,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
         final InvoicePayment paymentJson = setupScenarioWithPayment(true);
 
         // Get the individual items for the invoice
-        final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true, false, requestOptions);
+        final Invoice invoice = invoiceApi.getInvoice(paymentJson.getTargetInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         final InvoiceItem itemToAdjust = invoice.getItems().get(0);
 
         // Issue a refund for a fraction of the amount
@@ -197,7 +200,9 @@ public class TestInvoicePayment extends TestJaxrsBase {
         adjustment.setInvoiceItemId(itemToAdjust.getInvoiceItemId());
         adjustment.setAmount(refundAmount);
         refund.setAdjustments(ImmutableList.<InvoiceItem>of(adjustment));
-        final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+
+        invoicePaymentApi.createRefundWithAdjustments(paymentJson.getPaymentId(), refund, paymentJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment paymentAfterRefundJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
 
         // Verify the invoice balance
@@ -209,7 +214,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
         final InvoicePayment paymentJson = setupScenarioWithPayment(true);
 
         // Get the individual items for the invoice
-        final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true, false, requestOptions);
+        final Invoice invoice = invoiceApi.getInvoice(paymentJson.getTargetInvoiceId(), true, false, AuditLevel.NONE, requestOptions);
         final InvoiceItem itemToAdjust = invoice.getItems().get(0);
 
         // Issue a refund for a fraction of the amount
@@ -226,7 +231,9 @@ public class TestInvoicePayment extends TestJaxrsBase {
         // Ask for an adjustment for the full amount (bigger than the refund amount)
         adjustment.setAmount(itemToAdjust.getAmount());
         refund.setAdjustments(ImmutableList.<InvoiceItem>of(adjustment));
-        final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+
+        invoicePaymentApi.createRefundWithAdjustments(paymentJson.getPaymentId(), refund, paymentJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment paymentAfterRefundJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
         // The refund did go through
         verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
@@ -243,27 +250,28 @@ public class TestInvoicePayment extends TestJaxrsBase {
             final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
             refund.setPaymentId(lastPayment.getPaymentId());
             refund.setAmount(lastPayment.getPurchasedAmount());
-            killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+
+            invoicePaymentApi.createRefundWithAdjustments(lastPayment.getPaymentId(), refund, lastPayment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
             final InvoicePayment invoicePayment = new InvoicePayment();
             invoicePayment.setPurchasedAmount(lastPayment.getPurchasedAmount());
             invoicePayment.setAccountId(lastPayment.getAccountId());
             invoicePayment.setTargetInvoiceId(lastPayment.getTargetInvoiceId());
-            final InvoicePayment payment = killBillClient.createInvoicePayment(invoicePayment, false, requestOptions);
+            final InvoicePayment payment = invoiceApi.createInstantPayment(lastPayment.getTargetInvoiceId(), invoicePayment, NULL_PLUGIN_PROPERTIES, requestOptions);
             lastPayment = payment;
         }
 
-        final InvoicePayments allPayments = killBillClient.getInvoicePaymentsForAccount(lastPayment.getAccountId(), requestOptions);
+        final InvoicePayments allPayments = accountApi.getInvoicePayments(lastPayment.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(allPayments.size(), 6);
 
-        final List<PaymentTransaction> objRefundFromJson = getPaymentTransactions(allPayments, TransactionType.REFUND.toString());
+        final List<PaymentTransaction> objRefundFromJson = getInvoicePaymentTransactions(allPayments, TransactionType.REFUND);
         Assert.assertEquals(objRefundFromJson.size(), 5);
 
-        Payments paymentsPage = killBillClient.getPayments(0L, 1L, requestOptions);
+        Payments paymentsPage = paymentApi.getPayments(0L, 1L, null, false, false, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 6; i++) {
             Assert.assertNotNull(paymentsPage);
             Assert.assertEquals(paymentsPage.size(), 1);
-            Assert.assertTrue(paymentsPage.get(0).equals((Payment) allPayments.get(i)));
+            verifyInvoicePaymentAgainstPayment(allPayments.get(i), paymentsPage.get(0));
             paymentsPage = paymentsPage.getNext();
         }
         assertNull(paymentsPage);
@@ -279,22 +287,22 @@ public class TestInvoicePayment extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice(false);
 
-        InvoicePayments invoicePayments = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        InvoicePayments invoicePayments = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(invoicePayments.size(), 1);
 
         final InvoicePayment invoicePayment = invoicePayments.get(0);
         // Verify targetInvoiceId is not Null. See #593
         assertNotNull(invoicePayment.getTargetInvoiceId());
 
-        final Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 2);
         final Invoice invoice = invoices.get(1);
         // Verify this is the correct value
         assertEquals(invoicePayment.getTargetInvoiceId(), invoice.getInvoiceId());
 
         // Make a payment and verify both invoice payment point to the same targetInvoiceId
-        killBillClient.payAllInvoices(accountJson.getAccountId(), false, null, requestOptions);
-        invoicePayments = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        accountApi.payAllInvoices(accountJson.getAccountId(), false, null, NULL_PLUGIN_PROPERTIES, requestOptions);
+        invoicePayments = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(invoicePayments.size(), 2);
         for (final InvoicePayment cur : invoicePayments) {
             assertEquals(cur.getTargetInvoiceId(), invoice.getInvoiceId());
@@ -308,12 +316,12 @@ public class TestInvoicePayment extends TestJaxrsBase {
 
         // Disable automatic payments
         callbackServlet.pushExpectedEvent(ExtBusEventType.TAG_CREATION);
-        killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.AUTO_PAY_OFF.getId(), requestOptions);
+        accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(ControlTagType.AUTO_PAY_OFF.getId()), requestOptions);
         callbackServlet.assertListenerStatus();
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
-                                                                ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        final Subscription subscriptionJson = createSubscription(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
         assertNotNull(subscriptionJson);
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE,
@@ -321,7 +329,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
         clock.addDays(32);
         callbackServlet.assertListenerStatus();
 
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         assertEquals(invoices.size(), 2);
 
         final InvoicePayment invoicePayment1 = new InvoicePayment();
@@ -331,7 +339,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
 
         // Pay too too much => 400
         try {
-            killBillClient.createInvoicePayment(invoicePayment1, false, requestOptions);
+            invoiceApi.createInstantPayment(invoicePayment1.getTargetInvoiceId(), invoicePayment1, NULL_PLUGIN_PROPERTIES, requestOptions);
             Assert.fail("InvoicePayment call should fail with 400");
         } catch (final KillBillClientException e) {
             assertTrue(true);
@@ -343,12 +351,12 @@ public class TestInvoicePayment extends TestJaxrsBase {
         invoicePayment2.setTargetInvoiceId(invoices.get(1).getInvoiceId());
 
         // Just right, Yah! => 201
-        final InvoicePayment result2 = killBillClient.createInvoicePayment(invoicePayment2, false, requestOptions);
+        final InvoicePayment result2 = invoiceApi.createInstantPayment(invoicePayment2.getTargetInvoiceId(), invoicePayment2, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(result2.getTransactions().size(), 1);
         assertTrue(result2.getTransactions().get(0).getAmount().compareTo(invoices.get(1).getBalance()) == 0);
 
         // Already paid -> 204
-        final InvoicePayment result3 = killBillClient.createInvoicePayment(invoicePayment2, false, requestOptions);
+        final InvoicePayment result3 = invoiceApi.createInstantPayment(invoicePayment2.getTargetInvoiceId(), invoicePayment2, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertNull(result3);
     }
 
@@ -359,39 +367,39 @@ public class TestInvoicePayment extends TestJaxrsBase {
     private InvoicePayment setupScenarioWithPayment(final boolean invoicePaymentSuccess) throws Exception {
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice("Shotgun", invoicePaymentSuccess, true);
 
-        final List<InvoicePayment> paymentsForAccount = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final List<InvoicePayment> paymentsForAccount = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(paymentsForAccount.size(), 1);
 
         final InvoicePayment paymentJson = paymentsForAccount.get(0);
 
         // Check the PaymentMethod from paymentMethodId returned in the Payment object
         final UUID paymentMethodId = paymentJson.getPaymentMethodId();
-        final PaymentMethod paymentMethodJson = killBillClient.getPaymentMethod(paymentMethodId, true, requestOptions);
+        final PaymentMethod paymentMethodJson = paymentMethodApi.getPaymentMethod(paymentMethodId, NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(paymentMethodJson.getPaymentMethodId(), paymentMethodId);
         Assert.assertEquals(paymentMethodJson.getAccountId(), accountJson.getAccountId());
 
         // Verify the refunds
-        final List<PaymentTransaction> objRefundFromJson = getPaymentTransactions(paymentsForAccount, TransactionType.REFUND.toString());
+        final List<PaymentTransaction> objRefundFromJson = getInvoicePaymentTransactions(paymentsForAccount, TransactionType.REFUND);
         Assert.assertEquals(objRefundFromJson.size(), 0);
         return paymentJson;
     }
 
     private void verifyRefund(final InvoicePayment paymentJson, final Payment paymentAfterRefund, final BigDecimal refundAmount) throws KillBillClientException {
 
-        final List<PaymentTransaction> transactions = getPaymentTransactions(ImmutableList.of(paymentAfterRefund), TransactionType.REFUND.toString());
+        final List<PaymentTransaction> transactions = getPaymentTransactions(ImmutableList.of(paymentAfterRefund), TransactionType.REFUND);
         Assert.assertEquals(transactions.size(), 1);
 
         final PaymentTransaction refund = transactions.get(0);
         Assert.assertEquals(refund.getPaymentId(), paymentJson.getPaymentId());
         Assert.assertEquals(refund.getAmount().setScale(2, RoundingMode.HALF_UP), refundAmount.setScale(2, RoundingMode.HALF_UP));
         Assert.assertEquals(refund.getCurrency(), DEFAULT_CURRENCY);
-        Assert.assertEquals(refund.getStatus(), "SUCCESS");
+        Assert.assertEquals(refund.getStatus(), TransactionStatus.SUCCESS);
         Assert.assertEquals(refund.getEffectiveDate().getYear(), clock.getUTCNow().getYear());
         Assert.assertEquals(refund.getEffectiveDate().getMonthOfYear(), clock.getUTCNow().getMonthOfYear());
         Assert.assertEquals(refund.getEffectiveDate().getDayOfMonth(), clock.getUTCNow().getDayOfMonth());
 
         // Verify the refund via the payment API
-        final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), true, requestOptions);
+        final Payment retrievedPaymentJson = paymentApi.getPayment(paymentJson.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(retrievedPaymentJson.getPaymentId(), paymentJson.getPaymentId());
         Assert.assertEquals(retrievedPaymentJson.getPurchasedAmount().setScale(2, RoundingMode.HALF_UP), paymentJson.getPurchasedAmount().setScale(2, RoundingMode.HALF_UP));
         Assert.assertEquals(retrievedPaymentJson.getAccountId(), paymentJson.getAccountId());
@@ -400,8 +408,23 @@ public class TestInvoicePayment extends TestJaxrsBase {
     }
 
     private void verifyInvoice(final InvoicePayment paymentJson, final BigDecimal expectedInvoiceBalance) throws KillBillClientException {
-        final Invoice invoiceJson = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), requestOptions);
+        final Invoice invoiceJson = invoiceApi.getInvoice(paymentJson.getTargetInvoiceId(), requestOptions);
         Assert.assertEquals(invoiceJson.getBalance().setScale(2, BigDecimal.ROUND_HALF_UP),
                             expectedInvoiceBalance.setScale(2, BigDecimal.ROUND_HALF_UP));
     }
+
+    private void verifyInvoicePaymentAgainstPayment(final InvoicePayment ip, final Payment p) {
+        Assert.assertEquals(ip.getAccountId(), p.getAccountId());
+        Assert.assertEquals(ip.getPaymentId(), p.getPaymentId());
+        Assert.assertEquals(ip.getPaymentNumber(), p.getPaymentNumber());
+        Assert.assertEquals(ip.getAccountId(), p.getAccountId());
+        Assert.assertEquals(ip.getAuthAmount(), p.getAuthAmount());
+        Assert.assertEquals(ip.getCapturedAmount(), p.getCapturedAmount());
+        Assert.assertEquals(ip.getPurchasedAmount(), p.getPurchasedAmount());
+        Assert.assertEquals(ip.getRefundedAmount(), p.getRefundedAmount());
+        Assert.assertEquals(ip.getCreditedAmount(), p.getCreditedAmount());
+        Assert.assertEquals(ip.getCurrency(), p.getCurrency());
+        Assert.assertEquals(ip.getPaymentMethodId(), p.getPaymentMethodId());
+    }
+
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceVoid.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceVoid.java
index 6a79b16..1836734 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceVoid.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoiceVoid.java
@@ -27,12 +27,12 @@ import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.killbill.billing.client.model.InvoicePaymentTransaction;
 import org.killbill.billing.client.model.InvoicePayments;
-import org.killbill.billing.client.model.PaymentTransaction;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
 import org.killbill.billing.invoice.api.InvoiceStatus;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.payment.api.TransactionType;
@@ -52,41 +52,41 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         assertNotNull(accountJson);
 
         // Verify we didn't get any invoicePayment
-        final List<InvoicePayment> noPaymentsFromJson = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final List<InvoicePayment> noPaymentsFromJson = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(noPaymentsFromJson.size(), 0);
 
         // Get the invoices
-        List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
         // verify account balance
-        Account account = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        Account account = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(account.getAccountBalance().compareTo(invoices.get(1).getBalance()), 0);
 
         // void the invoice
-        killBillClient.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
+        invoiceApi.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
 
         // Get the invoices excluding voided
-        invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // the voided invoice should not be returned
         assertEquals(invoices.size(), 1);
 
         // Get the invoices including voided
-        invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, true, true, AuditLevel.NONE, requestOptions);
+        invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, true, AuditLevel.NONE, requestOptions);
         assertEquals(invoices.size(), 2);
-        assertEquals(invoices.get(1).getStatus(), InvoiceStatus.VOID.toString());
+        assertEquals(invoices.get(1).getStatus(), InvoiceStatus.VOID);
         assertEquals(invoices.get(1).getBalance().compareTo(BigDecimal.ZERO), 0);
 
         // check that account balance is zero
-        account = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        account = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(account.getAccountBalance().compareTo(BigDecimal.ZERO), 0);
 
         // After invoice was voided verify the subscription is re-invoiced on a new invoice
         // trigger an invoice generation
-        killBillClient.createInvoice(accountJson.getAccountId(), clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), requestOptions);
+        invoiceApi.createFutureInvoice(accountJson.getAccountId(), clock.getToday(DateTimeZone.forID(accountJson.getTimeZone())), requestOptions);
 
         // Get the invoices excluding voided
-        invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // the voided invoice should not be returned
         assertEquals(invoices.size(), 2);
 
@@ -95,7 +95,7 @@ public class TestInvoiceVoid extends TestJaxrsBase {
 
         // try to void invoice
         try {
-            killBillClient.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
+            invoiceApi.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
             Assert.fail("VoidInvoice call should fail with 400");
         } catch (final KillBillClientException e) {
             assertTrue(true);
@@ -106,13 +106,13 @@ public class TestInvoiceVoid extends TestJaxrsBase {
 
         // try to void invoice
         try {
-            killBillClient.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
+            invoiceApi.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
         } catch (final KillBillClientException e) {
             assertTrue(false);
         }
 
         // check that account balance is zero
-        account = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        account = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(account.getAccountBalance().compareTo(BigDecimal.ZERO), 0);
 
     }
@@ -123,15 +123,15 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         assertNotNull(accountJson);
 
         // Verify we didn't get any invoicePayment
-        final List<InvoicePayment> noPaymentsFromJson = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
+        final List<InvoicePayment> noPaymentsFromJson = accountApi.getInvoicePayments(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(noPaymentsFromJson.size(), 0);
 
         // Get the invoices
-        List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
         // verify account balance
-        Account account = killBillClient.getAccount(accountJson.getAccountId(), true, true, requestOptions);
+        Account account = accountApi.getAccount(accountJson.getAccountId(), true, true, AuditLevel.NONE, requestOptions);
         assertEquals(account.getAccountBalance().compareTo(invoices.get(1).getBalance()), 0);
 
         // process payment
@@ -139,7 +139,7 @@ public class TestInvoiceVoid extends TestJaxrsBase {
 
         // try to void invoice
         try {
-            killBillClient.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
+            invoiceApi.voidInvoice(invoices.get(1).getInvoiceId(), requestOptions);
             Assert.fail("VoidInvoice call should fail with 400");
         } catch (final KillBillClientException e) {
             assertTrue(true);
@@ -157,25 +157,25 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         final Account childAccount1 = createAccount(parentAccount.getAccountId());
 
         // Add a bundle and subscription
-        createEntitlement(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
-                          ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+                           ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
         // trigger an invoice generation
         callbackServlet.pushExpectedEvent(ExtBusEventType.INVOICE_CREATION);
-        killBillClient.createInvoice(childAccount1.getAccountId(), triggeredDate, requestOptions);
+        invoiceApi.createFutureInvoice(childAccount1.getAccountId(), triggeredDate, requestOptions);
         callbackServlet.assertListenerStatus();
-        List<Invoice> child1Invoices = killBillClient.getInvoicesForAccount(childAccount1.getAccountId(), true, false, requestOptions);
+        List<Invoice> child1Invoices = accountApi.getInvoicesForAccount(childAccount1.getAccountId(), true, false, false, true, AuditLevel.NONE, requestOptions);
         assertEquals(child1Invoices.size(), 2);
 
         // move one day so that the parent invoice is committed
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION, ExtBusEventType.INVOICE_PAYMENT_FAILED);
         clock.addDays(1);
         callbackServlet.assertListenerStatus();
-        List<Invoice> parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        List<Invoice> parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoices.size(), 1);
 
         // try to void child invoice
-        killBillClient.voidInvoice(child1Invoices.get(1).getInvoiceId(), requestOptions);
+        invoiceApi.voidInvoice(child1Invoices.get(1).getInvoiceId(), requestOptions);
 
         //  move the clock 1 month to check if invoices change
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE,
@@ -189,11 +189,11 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // The parent added another invoice, now it has two (duplicate)
-        parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoices.size(), 2);
 
         // the child added one invoice as expected
-        child1Invoices = killBillClient.getInvoicesForAccount(childAccount1.getAccountId(), true, false, requestOptions);
+        child1Invoices = accountApi.getInvoicesForAccount(childAccount1.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(child1Invoices.size(), 2);
     }
 
@@ -207,25 +207,25 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         final Account childAccount1 = createAccount(parentAccount.getAccountId());
 
         // Add a bundle and subscription
-        createEntitlement(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
-                          ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+        createSubscription(childAccount1.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+                           ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
         // trigger an invoice generation
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION);
-        killBillClient.createInvoice(childAccount1.getAccountId(), triggeredDate, requestOptions);
+        invoiceApi.createFutureInvoice(childAccount1.getAccountId(), triggeredDate, requestOptions);
         callbackServlet.assertListenerStatus();
-        List<Invoice> child1Invoices = killBillClient.getInvoicesForAccount(childAccount1.getAccountId(), true, false, requestOptions);
+        List<Invoice> child1Invoices = accountApi.getInvoicesForAccount(childAccount1.getAccountId(), true, false, false, true, AuditLevel.NONE, requestOptions);
         assertEquals(child1Invoices.size(), 2);
 
         // move one day so that the parent invoice is committed
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION, ExtBusEventType.INVOICE_PAYMENT_FAILED);
         clock.addDays(1);
         callbackServlet.assertListenerStatus();
-        List<Invoice> parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        List<Invoice> parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoices.size(), 1);
 
         // try to void parent invoice
-        killBillClient.voidInvoice(parentInvoices.get(0).getInvoiceId(), requestOptions);
+        invoiceApi.voidInvoice(parentInvoices.get(0).getInvoiceId(), requestOptions);
 
         //  move the clock 1 month to check if invoices change
         callbackServlet.pushExpectedEvents(ExtBusEventType.SUBSCRIPTION_PHASE);
@@ -234,11 +234,11 @@ public class TestInvoiceVoid extends TestJaxrsBase {
 
         // since the child did not have any change, the parent does not have an invoice
         // after the void.
-        parentInvoices = killBillClient.getInvoicesForAccount(parentAccount.getAccountId(), true, false, requestOptions);
+        parentInvoices = accountApi.getInvoicesForAccount(parentAccount.getAccountId(), true, false, false, false, AuditLevel.NONE, requestOptions);
         assertEquals(parentInvoices.size(), 0);
 
         // the child does not have any change
-        child1Invoices = killBillClient.getInvoicesForAccount(childAccount1.getAccountId(), true, false, requestOptions);
+        child1Invoices = accountApi.getInvoicesForAccount(childAccount1.getAccountId(), true, false, false, true, AuditLevel.NONE, requestOptions);
         assertEquals(child1Invoices.size(), 2);
     }
 
@@ -250,7 +250,7 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         invoicePayment.setAccountId(accountJson.getAccountId());
         invoicePayment.setTargetInvoiceId(invoice.getInvoiceId());
 
-        final InvoicePayment result = killBillClient.createInvoicePayment(invoicePayment, false, requestOptions);
+        final InvoicePayment result = invoiceApi.createInstantPayment(invoice.getInvoiceId(), invoicePayment, true, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(result.getTransactions().size(), 1);
         assertTrue(result.getTransactions().get(0).getAmount().compareTo(payAmount) == 0);
 
@@ -262,12 +262,12 @@ public class TestInvoiceVoid extends TestJaxrsBase {
         final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
         refund.setPaymentId(payment.getPaymentId());
         refund.setAmount(payment.getPurchasedAmount());
-        killBillClient.createInvoicePaymentRefund(refund, requestOptions);
+        invoicePaymentApi.createRefundWithAdjustments(payment.getPaymentId(), refund, payment.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final InvoicePayments allPayments = killBillClient.getInvoicePaymentsForAccount(payment.getAccountId(), requestOptions);
+        final InvoicePayments allPayments = accountApi.getInvoicePayments(payment.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(allPayments.size(), 1);
 
-        final List<PaymentTransaction> objRefundFromJson = getPaymentTransactions(allPayments, TransactionType.REFUND.toString());
+        final List<PaymentTransaction> objRefundFromJson = getInvoicePaymentTransactions(allPayments, TransactionType.REFUND);
         assertEquals(objRefundFromJson.size(), 1);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
index a464a62..ea7bbee 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
@@ -18,9 +18,12 @@
 
 package org.killbill.billing.jaxrs;
 
+import java.io.File;
+import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadInfo;
 import java.lang.management.ThreadMXBean;
+import java.nio.charset.Charset;
 import java.util.EventListener;
 import java.util.Iterator;
 import java.util.List;
@@ -39,12 +42,35 @@ import org.joda.time.LocalDate;
 import org.killbill.billing.GuicyKillbillTestWithEmbeddedDBModule;
 import org.killbill.billing.api.TestApiListener;
 import org.killbill.billing.beatrix.integration.db.TestDBRouterAPI;
-import org.killbill.billing.client.KillBillClient;
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.KillBillHttpClient;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentTransaction;
-import org.killbill.billing.client.model.Tenant;
+import org.killbill.billing.client.api.gen.AccountApi;
+import org.killbill.billing.client.api.gen.AdminApi;
+import org.killbill.billing.client.api.gen.BundleApi;
+import org.killbill.billing.client.api.gen.CatalogApi;
+import org.killbill.billing.client.api.gen.CreditApi;
+import org.killbill.billing.client.api.gen.CustomFieldApi;
+import org.killbill.billing.client.api.gen.ExportApi;
+import org.killbill.billing.client.api.gen.InvoiceApi;
+import org.killbill.billing.client.api.gen.InvoiceItemApi;
+import org.killbill.billing.client.api.gen.InvoicePaymentApi;
+import org.killbill.billing.client.api.gen.NodesInfoApi;
+import org.killbill.billing.client.api.gen.OverdueApi;
+import org.killbill.billing.client.api.gen.PaymentApi;
+import org.killbill.billing.client.api.gen.PaymentGatewayApi;
+import org.killbill.billing.client.api.gen.PaymentMethodApi;
+import org.killbill.billing.client.api.gen.PaymentTransactionApi;
+import org.killbill.billing.client.api.gen.PluginInfoApi;
+import org.killbill.billing.client.api.gen.SecurityApi;
+import org.killbill.billing.client.api.gen.SubscriptionApi;
+import org.killbill.billing.client.api.gen.TagApi;
+import org.killbill.billing.client.api.gen.TagDefinitionApi;
+import org.killbill.billing.client.api.gen.TenantApi;
+import org.killbill.billing.client.api.gen.UsageApi;
+import org.killbill.billing.client.model.gen.InvoicePayment;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.Tenant;
 import org.killbill.billing.invoice.glue.DefaultInvoiceModule;
 import org.killbill.billing.jaxrs.resources.TestDBRouterResource;
 import org.killbill.billing.jetty.HttpServer;
@@ -52,6 +78,7 @@ import org.killbill.billing.jetty.HttpServerConfig;
 import org.killbill.billing.lifecycle.glue.BusModule;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.glue.PaymentModule;
 import org.killbill.billing.payment.provider.MockPaymentProviderPluginModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
@@ -79,6 +106,8 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
 import com.google.inject.Binder;
 import com.google.inject.Module;
 import com.google.inject.util.Modules;
@@ -185,6 +214,11 @@ public class TestJaxrsBase extends KillbillClient {
     }
 
     protected void setupClient(final String username, final String password, final String apiKey, final String apiSecret) {
+        requestOptions = requestOptions.extend()
+                                       .withTenantApiKey(apiKey)
+                                       .withTenantApiSecret(apiSecret)
+                                       .build();
+
         killBillHttpClient = new KillBillHttpClient(String.format("http://%s:%d", config.getServerHost(), config.getServerPort()),
                                                     username,
                                                     password,
@@ -195,7 +229,29 @@ public class TestJaxrsBase extends KillbillClient {
                                                     DEFAULT_CONNECT_TIMEOUT_SEC * 1000,
                                                     DEFAULT_READ_TIMEOUT_SEC * 1000,
                                                     DEFAULT_REQUEST_TIMEOUT_SEC * 1000);
-        killBillClient = new KillBillClient(killBillHttpClient);
+        accountApi = new AccountApi(killBillHttpClient);
+        adminApi = new AdminApi(killBillHttpClient);
+        bundleApi = new BundleApi(killBillHttpClient);
+        catalogApi = new CatalogApi(killBillHttpClient);
+        creditApi = new CreditApi(killBillHttpClient);
+        customFieldApi = new CustomFieldApi(killBillHttpClient);
+        exportApi = new ExportApi(killBillHttpClient);
+        invoiceApi = new InvoiceApi(killBillHttpClient);
+        invoiceItemApi = new InvoiceItemApi(killBillHttpClient);
+        invoicePaymentApi = new InvoicePaymentApi(killBillHttpClient);
+        nodesInfoApi = new NodesInfoApi(killBillHttpClient);
+        overdueApi = new OverdueApi(killBillHttpClient);
+        paymentApi = new PaymentApi(killBillHttpClient);
+        paymentGatewayApi = new PaymentGatewayApi(killBillHttpClient);
+        paymentMethodApi = new PaymentMethodApi(killBillHttpClient);
+        paymentTransactionApi = new PaymentTransactionApi(killBillHttpClient);
+        pluginInfoApi = new PluginInfoApi(killBillHttpClient);
+        securityApi = new SecurityApi(killBillHttpClient);
+        subscriptionApi = new SubscriptionApi(killBillHttpClient);
+        tagApi = new TagApi(killBillHttpClient);
+        tagDefinitionApi = new TagDefinitionApi(killBillHttpClient);
+        tenantApi = new TenantApi(killBillHttpClient);
+        usageApi = new UsageApi(killBillHttpClient);
     }
 
     protected void loginTenant(final String apiKey, final String apiSecret) {
@@ -206,10 +262,6 @@ public class TestJaxrsBase extends KillbillClient {
         setupClient(USERNAME, PASSWORD, null, null);
     }
 
-    protected void login() {
-        login(USERNAME, PASSWORD);
-    }
-
     protected void login(final String username, final String password) {
         setupClient(username, password, DEFAULT_API_KEY, DEFAULT_API_SECRET);
     }
@@ -266,11 +318,11 @@ public class TestJaxrsBase extends KillbillClient {
             callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
         }
 
-        final Tenant createdTenant = killBillClient.createTenant(tenant, useGlobalDefault, requestOptions);
+        final Tenant createdTenant = tenantApi.createTenant(tenant, useGlobalDefault, requestOptions);
 
         // Register tenant for callback
         final String callback = callbackServer.getServletEndpoint();
-        killBillClient.registerCallbackNotificationForTenant(callback, requestOptions);
+        tenantApi.registerPushNotificationCallback(callback, requestOptions);
         callbackServlet.assertListenerStatus();
 
         createdTenant.setApiSecret(apiSecret);
@@ -284,7 +336,7 @@ public class TestJaxrsBase extends KillbillClient {
             return;
         }
 
-        killBillClient.close();
+        killBillHttpClient.close();
         externalBus.stop();
         internalBus.stop();
     }
@@ -332,7 +384,6 @@ public class TestJaxrsBase extends KillbillClient {
         callbackServer.startServer();
     }
 
-
     protected Iterable<EventListener> getListeners() {
         return new Iterable<EventListener>() {
             @Override
@@ -357,18 +408,52 @@ public class TestJaxrsBase extends KillbillClient {
         }
     }
 
-    protected static <T extends Payment> List<PaymentTransaction> getPaymentTransactions(final List<T> payments, final String transactionType) {
-        return ImmutableList.copyOf(Iterables.concat(Iterables.transform(payments, new Function<T, Iterable<PaymentTransaction>>() {
+    protected static List<PaymentTransaction> getInvoicePaymentTransactions(final List<InvoicePayment> payments, final TransactionType transactionType) {
+        final Iterable<PaymentTransaction> transform = Iterables.concat(Iterables.transform(payments, new Function<InvoicePayment, Iterable<PaymentTransaction>>() {
+            @Override
+            public Iterable<PaymentTransaction> apply(final InvoicePayment input) {
+                return input.getTransactions();
+            }
+        }));
+        return filterTransactions(transform, transactionType);
+    }
+
+    protected static List<PaymentTransaction> getPaymentTransactions(final List<Payment> payments, final TransactionType transactionType) {
+        final Iterable<PaymentTransaction> transform = Iterables.concat(Iterables.transform(payments, new Function<Payment, Iterable<PaymentTransaction>>() {
             @Override
-            public Iterable<PaymentTransaction> apply(final T input) {
-                return Iterables.filter(input.getTransactions(), new Predicate<PaymentTransaction>() {
-                    @Override
-                    public boolean apply(final PaymentTransaction input) {
-                        return input.getTransactionType().equals(transactionType);
-                    }
-                });
+            public Iterable<PaymentTransaction> apply(final Payment input) {
+                return input.getTransactions();
             }
-        })));
+        }));
+        return filterTransactions(transform, transactionType);
+    }
+
+    protected static List<PaymentTransaction> filterTransactions(final Iterable<PaymentTransaction> paymentTransaction, final TransactionType transactionType) {
+        return ImmutableList.copyOf(Iterables.filter(paymentTransaction, new Predicate<PaymentTransaction>() {
+            @Override
+            public boolean apply(final PaymentTransaction input) {
+                return input.getTransactionType().equals(transactionType);
+            }
+        }));
+    }
+
+    protected String uploadTenantCatalog(final String catalog, final boolean fetch) throws IOException, KillBillClientException {
+        final String body = getResourceBodyString(catalog);
+        catalogApi.uploadCatalogXml(body, requestOptions);
+        return fetch ? catalogApi.getCatalogXml(null, null, requestOptions) : null;
+    }
+
+    protected void uploadTenantOverdueConfig(final String overdue) throws IOException, KillBillClientException {
+        final String body = getResourceBodyString(overdue);
+        callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
+        overdueApi.uploadOverdueConfigXml(body, requestOptions);
+        callbackServlet.assertListenerStatus();
+    }
+
+    protected String getResourceBodyString(final String resource) throws IOException {
+        final String resourcePath = Resources.getResource(resource).getPath();
+        final File catalogFile = new File(resourcePath);
+        return Files.toString(catalogFile, Charset.forName("UTF-8"));
     }
 
     protected void printThreadDump() {
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
index 0c8124e..0c1e17e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
@@ -21,19 +21,20 @@ package org.killbill.billing.jaxrs;
 import java.math.BigDecimal;
 import java.util.Comparator;
 import java.util.List;
+import java.util.UUID;
 
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Invoice;
-import org.killbill.billing.client.model.InvoicePayment;
 import org.killbill.billing.client.model.Invoices;
 import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Invoice;
+import org.killbill.billing.client.model.gen.InvoicePayment;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
-import com.google.common.io.Resources;
 
 import static org.testng.Assert.assertEquals;
 
@@ -41,10 +42,9 @@ public class TestOverdue extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Upload and retrieve a per tenant overdue config")
     public void testMultiTenantOverdueConfig() throws Exception {
-        final String overdueConfigPath = Resources.getResource("overdue.xml").getPath();
-        killBillClient.uploadXMLOverdueConfig(overdueConfigPath, requestOptions);
+        uploadTenantOverdueConfig("overdue.xml");
 
-        final String overdueConfig = killBillClient.getXMLOverdueConfig(requestOptions);
+        final String overdueConfig = overdueApi.getOverdueConfigXml(requestOptions);
         Assert.assertNotNull(overdueConfig);
     }
 
@@ -54,32 +54,32 @@ public class TestOverdue extends TestJaxrsBase {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
 
         // We're still clear - see the configuration
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).isClearState());
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION, ExtBusEventType.INVOICE_PAYMENT_FAILED, ExtBusEventType.BLOCKING_STATE, ExtBusEventType.OVERDUE_CHANGE);
         clock.addDays(30);
         callbackServlet.assertListenerStatus();
-        Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getName(), "OD1");
+        Assert.assertEquals(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).getName(), "OD1");
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.TAG_CREATION, ExtBusEventType.BLOCKING_STATE, ExtBusEventType.OVERDUE_CHANGE);
         clock.addDays(10);
         callbackServlet.assertListenerStatus();
-        Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getName(), "OD2");
+        Assert.assertEquals(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).getName(), "OD2");
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.BLOCKING_STATE, ExtBusEventType.OVERDUE_CHANGE);
         clock.addDays(10);
         callbackServlet.assertListenerStatus();
-        Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getName(), "OD3");
+        Assert.assertEquals(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).getName(), "OD3");
 
         // Post external payments, paying the most recent invoice first: this is to avoid a race condition where
         // a refresh overdue notification kicks in after the first payment, which makes the account goes CLEAR and
         // triggers an AUTO_INVOICE_OFF tag removal (hence adjustment of the other invoices balance).
-        final Invoices invoicesForAccount = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final Invoices invoicesForAccount = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         final List<Invoice> mostRecentInvoiceFirst = Ordering.<Invoice>from(new Comparator<Invoice>() {
             @Override
             public int compare(final Invoice invoice1, final Invoice invoice2) {
@@ -93,7 +93,7 @@ public class TestOverdue extends TestJaxrsBase {
                 invoicePayment.setAccountId(accountJson.getAccountId());
                 invoicePayment.setTargetInvoiceId(invoice.getInvoiceId());
                 callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_PAYMENT_SUCCESS, ExtBusEventType.PAYMENT_SUCCESS);
-                killBillClient.createInvoicePayment(invoicePayment, true, requestOptions);
+                invoiceApi.createInstantPayment(invoice.getInvoiceId(), invoicePayment, true, NULL_PLUGIN_PROPERTIES, requestOptions);
                 callbackServlet.assertListenerStatus();
             }
         }
@@ -103,20 +103,17 @@ public class TestOverdue extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Verify we're in clear state
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).isClearState());
     }
 
     @Test(groups = "slow", description = "Allow overdue condition by control tag defined in overdue config xml file")
     public void testControlTagOverdueConfig() throws Exception {
-        callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        final String overdueConfigPath = Resources.getResource("overdueWithControlTag.xml").getPath();
-        killBillClient.uploadXMLOverdueConfig(overdueConfigPath, requestOptions);
-        callbackServlet.assertListenerStatus();
+        uploadTenantOverdueConfig("overdueWithControlTag.xml");
 
         // Create an account without a payment method and assign a TEST tag
         final Account accountJson = createAccountNoPMBundleAndSubscription();
         callbackServlet.pushExpectedEvent(ExtBusEventType.TAG_CREATION);
-        final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.TEST.getId(), requestOptions);
+        final Tags accountTag = accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(ControlTagType.TEST.getId()), requestOptions);
         callbackServlet.assertListenerStatus();
         assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.TEST.getId());
 
@@ -129,17 +126,17 @@ public class TestOverdue extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
 
-        final List<Invoice> invoicesNoTag = killBillClient.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
+        final List<Invoice> invoicesNoTag = accountApi.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoicesNoTag.size(), 2);
 
         // We're still clear - see the configuration
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).isClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJsonNoTag.getAccountId(), requestOptions).isClearState());
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION,
                                            ExtBusEventType.INVOICE_PAYMENT_FAILED,
@@ -151,22 +148,19 @@ public class TestOverdue extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // This account is expected to move to OD1 state because it matches with controlTag defined
-        Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getName(), "OD1");
+        Assert.assertEquals(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).getName(), "OD1");
         // This account is not expected to move to OD1 state because it does not match with controlTag defined
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJsonNoTag.getAccountId(), requestOptions).isClearState());
     }
 
     @Test(groups = "slow", description = "Allow overdue condition by exclusion control tag defined in overdue config xml file")
     public void testExclusionControlTagOverdueConfig() throws Exception {
-        callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        final String overdueConfigPath = Resources.getResource("overdueWithExclusionControlTag.xml").getPath();
-        killBillClient.uploadXMLOverdueConfig(overdueConfigPath, requestOptions);
-        callbackServlet.assertListenerStatus();
+        uploadTenantOverdueConfig("overdueWithExclusionControlTag.xml");
 
         // Create an account without a payment method and assign a TEST tag
         final Account accountJson = createAccountNoPMBundleAndSubscription();
         callbackServlet.pushExpectedEvent(ExtBusEventType.TAG_CREATION);
-        final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.TEST.getId(), requestOptions);
+        final Tags accountTag = accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(ControlTagType.TEST.getId()), requestOptions);
         callbackServlet.assertListenerStatus();
         assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.TEST.getId());
 
@@ -185,17 +179,17 @@ public class TestOverdue extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // Get the invoices
-        final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+        final List<Invoice> invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoices.size(), 2);
 
-        final List<Invoice> invoicesNoTag = killBillClient.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
+        final List<Invoice> invoicesNoTag = accountApi.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
         // 2 invoices but look for the non zero dollar one
         assertEquals(invoicesNoTag.size(), 2);
 
         // We're still clear - see the configuration
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).isClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJsonNoTag.getAccountId(), requestOptions).isClearState());
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_CREATION,
                                            ExtBusEventType.INVOICE_CREATION,
@@ -207,8 +201,8 @@ public class TestOverdue extends TestJaxrsBase {
         callbackServlet.assertListenerStatus();
 
         // This account is not expected to move to OD1 state because it does not match with exclusion controlTag defined
-        Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+        Assert.assertTrue(accountApi.getOverdueAccount(accountJson.getAccountId(), requestOptions).isClearState());
         // This account is expected to move to OD1 state because it matches with exclusion controlTag defined
-        Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getName(), "OD1");
+        Assert.assertEquals(accountApi.getOverdueAccount(accountJsonNoTag.getAccountId(), requestOptions).getName(), "OD1");
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index eb3e108..744d4bc 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -32,18 +32,18 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.ComboPaymentTransaction;
 import org.killbill.billing.client.model.InvoicePayments;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
-import org.killbill.billing.client.model.PaymentTransaction;
 import org.killbill.billing.client.model.Payments;
-import org.killbill.billing.client.model.PluginProperty;
-import org.killbill.billing.client.model.TagDefinition;
 import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.ComboPaymentTransaction;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.PluginProperty;
+import org.killbill.billing.client.model.gen.TagDefinition;
 import org.killbill.billing.control.plugin.api.PaymentControlPluginApi;
 import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
@@ -123,21 +123,19 @@ public class TestPayment extends TestJaxrsBase {
     public void testWithTransactionEffectiveDate() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
 
-
         final PaymentTransaction authTransaction = new PaymentTransaction();
         authTransaction.setAmount(BigDecimal.ONE);
         authTransaction.setCurrency(account.getCurrency());
-        authTransaction.setTransactionType(TransactionType.AUTHORIZE.name());
-        final DateTime effectiveDate = new DateTime(2018, 9,4, 3,5,35);
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
+        final DateTime effectiveDate = new DateTime(2018, 9, 4, 3, 5, 35);
         authTransaction.setEffectiveDate(effectiveDate);
 
-        final Payment payment = killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction,
-                                                             ImmutableMap.<String, String>of(), requestOptions);
+        final Payment payment = accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(),
+                                                          NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         final PaymentTransaction paymentTransaction = payment.getTransactions().get(0);
         assertTrue(paymentTransaction.getEffectiveDate().compareTo(effectiveDate) == 0);
     }
 
-
     @Test(groups = "slow")
     public void testWithFailedPayment() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
@@ -147,12 +145,12 @@ public class TestPayment extends TestJaxrsBase {
         final PaymentTransaction authTransaction = new PaymentTransaction();
         authTransaction.setAmount(BigDecimal.ONE);
         authTransaction.setCurrency(account.getCurrency());
-        authTransaction.setTransactionType(TransactionType.AUTHORIZE.name());
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
 
-        final Payment payment = killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction,
-                                                             ImmutableMap.<String, String>of(), requestOptions);
+        final Payment payment = accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(),
+                                                          NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         final PaymentTransaction paymentTransaction = payment.getTransactions().get(0);
-        assertEquals(paymentTransaction.getStatus(), TransactionStatus.PAYMENT_FAILURE.toString());
+        assertEquals(paymentTransaction.getStatus(), TransactionStatus.PAYMENT_FAILURE);
         assertEquals(paymentTransaction.getGatewayErrorCode(), MockPaymentProviderPlugin.GATEWAY_ERROR_CODE);
         assertEquals(paymentTransaction.getGatewayErrorMsg(), MockPaymentProviderPlugin.GATEWAY_ERROR);
     }
@@ -166,7 +164,7 @@ public class TestPayment extends TestJaxrsBase {
         final PaymentTransaction authTransaction = new PaymentTransaction();
         authTransaction.setAmount(BigDecimal.ONE);
         authTransaction.setCurrency(account.getCurrency());
-        authTransaction.setTransactionType(TransactionType.AUTHORIZE.name());
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
 
         final RequestOptions requestOptionsWithoutFollowLocation = RequestOptions.builder()
                                                                                  .withCreatedBy(createdBy)
@@ -176,8 +174,8 @@ public class TestPayment extends TestJaxrsBase {
                                                                                  .build();
 
         try {
-            killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction,
-                                         ImmutableMap.<String, String>of(), requestOptionsWithoutFollowLocation);
+            accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(),
+                                      NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptionsWithoutFollowLocation);
             fail();
         } catch (final KillBillClientException e) {
             assertEquals(e.getResponse().getStatusCode(), 402);
@@ -194,10 +192,12 @@ public class TestPayment extends TestJaxrsBase {
         final PaymentTransaction authTransaction = new PaymentTransaction();
         authTransaction.setAmount(BigDecimal.ONE);
         authTransaction.setCurrency(account.getCurrency());
-        authTransaction.setTransactionType(TransactionType.AUTHORIZE.name());
-        final Payment payment = killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction, ImmutableMap.<String, String>of(), requestOptions);
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
+
+        final Payment payment = accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(),
+                                                          NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         final PaymentTransaction paymentTransaction = payment.getTransactions().get(0);
-        assertEquals(paymentTransaction.getStatus(), TransactionStatus.PLUGIN_FAILURE.toString());
+        assertEquals(paymentTransaction.getStatus(), TransactionStatus.PLUGIN_FAILURE);
     }
 
     @Test(groups = "slow")
@@ -209,9 +209,10 @@ public class TestPayment extends TestJaxrsBase {
         final PaymentTransaction authTransaction = new PaymentTransaction();
         authTransaction.setAmount(BigDecimal.ONE);
         authTransaction.setCurrency(account.getCurrency());
-        authTransaction.setTransactionType(TransactionType.AUTHORIZE.name());
+        authTransaction.setTransactionType(TransactionType.AUTHORIZE);
         try {
-            killBillClient.createPayment(account.getAccountId(), account.getPaymentMethodId(), authTransaction, ImmutableMap.<String, String>of(), requestOptions);
+            accountApi.processPayment(account.getAccountId(), authTransaction, account.getPaymentMethodId(),
+                                      NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
             fail();
         } catch (KillBillClientException e) {
             assertEquals(504, e.getResponse().getStatusCode());
@@ -223,7 +224,7 @@ public class TestPayment extends TestJaxrsBase {
         mockPaymentProviderPlugin.makeNextPaymentFailWithError();
         final Account account = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice(false);
         // Getting Invoice #2 (first after Trial period)
-        UUID failedInvoiceId = killBillClient.getInvoicesForAccount(account.getAccountId(), false, false, RequestOptions.empty()).get(1).getInvoiceId();
+        UUID failedInvoiceId = accountApi.getInvoicesForAccount(account.getAccountId(), RequestOptions.empty()).get(1).getInvoiceId();
 
         HashMultimap<String, String> queryParams = HashMultimap.create();
         queryParams.put("withAttempts", "true");
@@ -233,7 +234,7 @@ public class TestPayment extends TestJaxrsBase {
                                                     .withComment(comment)
                                                     .withQueryParams(queryParams).build();
 
-        InvoicePayments invoicePayments = killBillClient.getInvoicePayment(failedInvoiceId, inputOptions);
+        InvoicePayments invoicePayments = invoiceApi.getPaymentsForInvoice(failedInvoiceId, inputOptions);
 
         Assert.assertEquals(invoicePayments.get(0).getTargetInvoiceId(), failedInvoiceId);
         Assert.assertNotNull(invoicePayments.get(0).getPaymentAttempts());
@@ -241,10 +242,9 @@ public class TestPayment extends TestJaxrsBase {
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(1).getStateName(), "SCHEDULED");
 
-
         // Remove the future notification and check SCHEDULED does not appear any longer
-        killBillClient.cancelScheduledPaymentTransaction(null, invoicePayments.get(0).getPaymentAttempts().get(1).getTransactionExternalKey(), inputOptions);
-        invoicePayments = killBillClient.getInvoicePayment(failedInvoiceId, inputOptions);
+        paymentApi.cancelScheduledPaymentTransactionByExternalKey(invoicePayments.get(0).getPaymentAttempts().get(1).getTransactionExternalKey(), inputOptions);
+        invoicePayments = invoiceApi.getPaymentsForInvoice(failedInvoiceId, inputOptions);
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().size(), 1);
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
     }
@@ -262,7 +262,7 @@ public class TestPayment extends TestJaxrsBase {
                                                     .withComment(comment)
                                                     .withQueryParams(queryParams).build();
 
-        Payments payments = killBillClient.getPaymentsForAccount(account.getAccountId(), inputOptions);
+        Payments payments = accountApi.getPaymentsForAccount(account.getAccountId(), NULL_PLUGIN_PROPERTIES, inputOptions);
 
         Assert.assertNotNull(payments.get(0).getPaymentAttempts());
         Assert.assertEquals(payments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
@@ -282,7 +282,7 @@ public class TestPayment extends TestJaxrsBase {
                                                     .withComment(comment)
                                                     .withQueryParams(queryParams).build();
 
-        Payments payments = killBillClient.getPayments(0L, 100L, null, new HashMap<String, String>(), AuditLevel.NONE, inputOptions);
+        Payments payments = paymentApi.getPayments(0L, 100L, null, false, true, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, inputOptions);
 
         Assert.assertNotNull(payments.get(0).getPaymentAttempts());
         Assert.assertEquals(payments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
@@ -302,7 +302,7 @@ public class TestPayment extends TestJaxrsBase {
                                                     .withComment(comment)
                                                     .withQueryParams(queryParams).build();
 
-        Payments payments = killBillClient.searchPayments("", 0L, 100L, AuditLevel.NONE, inputOptions);
+        Payments payments = paymentApi.searchPayments("", 0L, 100L, false, true, null, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, inputOptions);
 
         Assert.assertNotNull(payments.get(0).getPaymentAttempts());
         Assert.assertEquals(payments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
@@ -314,9 +314,9 @@ public class TestPayment extends TestJaxrsBase {
         mockPaymentProviderPlugin.makeNextPaymentFailWithError();
         createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice(false);
 
-        Payments payments = killBillClient.searchPayments("", 0L, 100L, AuditLevel.NONE, requestOptions);
+        Payments payments = paymentApi.searchPayments("", 0L, 100L, false, true, null, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
         Assert.assertNotNull(payments.get(0));
-        Payment payment = killBillClient.getPayment(payments.get(0).getPaymentId(), false, true, ImmutableMap.<String, String>of(), AuditLevel.NONE, requestOptions);
+        Payment payment = paymentApi.getPayment(payments.get(0).getPaymentId(), false, true, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
 
         Assert.assertNotNull(payment.getPaymentAttempts());
         Assert.assertEquals(payment.getPaymentAttempts().get(0).getStateName(), "RETRIED");
@@ -333,9 +333,9 @@ public class TestPayment extends TestJaxrsBase {
                                                     .withReason(reason)
                                                     .withComment(comment).build();
 
-        killBillClient.deletePaymentMethod(paymentMethodId, true, false, inputOptions);
+        paymentMethodApi.deletePaymentMethod(paymentMethodId, true, false, NULL_PLUGIN_PROPERTIES, inputOptions);
 
-        Tags accountTags = killBillClient.getAccountTags(account.getAccountId(), inputOptions);
+        Tags accountTags = accountApi.getAccountTags(account.getAccountId(), inputOptions);
 
         Assert.assertNotNull(accountTags);
         Assert.assertEquals(accountTags.get(0).getTagDefinitionName(), "AUTO_PAY_OFF");
@@ -347,11 +347,11 @@ public class TestPayment extends TestJaxrsBase {
         final String externalPaymentKey = UUID.randomUUID().toString();
         final UUID paymentId = testCreateRetrievePayment(account, null, externalPaymentKey, 1);
 
-        final Payment payment = killBillClient.getPaymentByExternalKey(externalPaymentKey);
+        final Payment payment = paymentApi.getPaymentByExternalKey(externalPaymentKey, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(payment.getPaymentId(), paymentId);
 
-        final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), account.getAccountId(), false, PLUGIN_NAME, new PaymentMethodPluginDetail());
-        final PaymentMethod nonDefaultPaymentMethod = killBillClient.createPaymentMethod(paymentMethodJson, createdBy, reason, comment);
+        final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), account.getAccountId(), false, PLUGIN_NAME, new PaymentMethodPluginDetail(), null);
+        final PaymentMethod nonDefaultPaymentMethod = accountApi.createPaymentMethod(account.getAccountId(), paymentMethodJson, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         testCreateRetrievePayment(account, nonDefaultPaymentMethod.getPaymentMethodId(), UUID.randomUUID().toString(), 2);
     }
 
@@ -371,34 +371,38 @@ public class TestPayment extends TestJaxrsBase {
             final String authTransactionExternalKey = UUID.randomUUID().toString();
             paymentNb++;
 
-            final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, authAmount, pluginProperties, paymentNb);
+            final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, authAmount, pluginProperties, paymentNb);
             final PaymentTransaction authPaymentTransaction = initialPayment.getTransactions().get(0);
 
             // Complete operation: first, only specify the payment id
             final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
             completeTransactionByPaymentId.setPaymentId(initialPayment.getPaymentId());
-            final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionByPaymentId, pluginProperties, requestOptions);
-            verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), pending, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
+            paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+            verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
 
             // Second, only specify the payment external key
             final PaymentTransaction completeTransactionByPaymentExternalKey = new PaymentTransaction();
             completeTransactionByPaymentExternalKey.setPaymentExternalKey(initialPayment.getPaymentExternalKey());
-            final Payment completedPaymentByExternalKey = killBillClient.completePayment(completeTransactionByPaymentExternalKey, pluginProperties, requestOptions);
-            verifyPayment(account, paymentMethodId, completedPaymentByExternalKey, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), pending, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
+            paymentApi.completeTransactionByExternalKey(completeTransactionByPaymentExternalKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            final Payment completedPaymentByExternalKey = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+            verifyPayment(account, paymentMethodId, completedPaymentByExternalKey, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
 
             // Third, specify the payment id and transaction external key
             final PaymentTransaction completeTransactionWithTypeAndKey = new PaymentTransaction();
-            completeTransactionWithTypeAndKey.setPaymentId(initialPayment.getPaymentId());
+            completeTransactionWithTypeAndKey.setPaymentExternalKey(paymentExternalKey);
             completeTransactionWithTypeAndKey.setTransactionExternalKey(authPaymentTransaction.getTransactionExternalKey());
-            final Payment completedPaymentByTypeAndKey = killBillClient.completePayment(completeTransactionWithTypeAndKey, pluginProperties, requestOptions);
-            verifyPayment(account, paymentMethodId, completedPaymentByTypeAndKey, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), pending, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
+            paymentApi.completeTransactionByExternalKey(completeTransactionWithTypeAndKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            final Payment completedPaymentByTypeAndKey = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+            verifyPayment(account, paymentMethodId, completedPaymentByTypeAndKey, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
 
             // Finally, specify the payment id and transaction id
             final PaymentTransaction completeTransactionWithTypeAndId = new PaymentTransaction();
             completeTransactionWithTypeAndId.setPaymentId(initialPayment.getPaymentId());
             completeTransactionWithTypeAndId.setTransactionId(authPaymentTransaction.getTransactionId());
-            final Payment completedPaymentByTypeAndId = killBillClient.completePayment(completeTransactionWithTypeAndId, pluginProperties, requestOptions);
-            verifyPayment(account, paymentMethodId, completedPaymentByTypeAndId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), pending, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
+            paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionWithTypeAndId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            final Payment completedPaymentByTypeAndId = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+            verifyPayment(account, paymentMethodId, completedPaymentByTypeAndId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
         }
     }
 
@@ -417,16 +421,16 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
 
         // Complete operation: first, only specify the payment id
         final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
         completeTransactionByPaymentId.setPaymentId(initialPayment.getPaymentId());
-        final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionByPaymentId, pluginProperties, requestOptions);
-        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), TransactionStatus.SUCCESS.name(), amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+        paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
     }
 
-
     @Test(groups = "slow")
     public void testAuthorizeCompletionUsingPaymentIdAndTransactionId() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
@@ -442,23 +446,23 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
-
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
 
         final PaymentTransaction completeTransactionByPaymentIdAndInvalidTransactionId = new PaymentTransaction();
         completeTransactionByPaymentIdAndInvalidTransactionId.setPaymentId(initialPayment.getPaymentId());
         completeTransactionByPaymentIdAndInvalidTransactionId.setTransactionId(UUID.randomUUID());
         try {
-            killBillClient.completePayment(completeTransactionByPaymentIdAndInvalidTransactionId, pluginProperties, requestOptions);
-            fail("Payment completion should fail when invalid transaction id has been provided" );
+            paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentIdAndInvalidTransactionId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            fail("Payment completion should fail when invalid transaction id has been provided");
         } catch (final KillBillClientException expected) {
         }
 
         final PaymentTransaction completeTransactionByPaymentIdAndTransactionId = new PaymentTransaction();
         completeTransactionByPaymentIdAndTransactionId.setPaymentId(initialPayment.getPaymentId());
         completeTransactionByPaymentIdAndTransactionId.setTransactionId(initialPayment.getTransactions().get(0).getTransactionId());
-        final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionByPaymentIdAndTransactionId, pluginProperties, requestOptions);
-        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), TransactionStatus.SUCCESS.name(), amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+        paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentIdAndTransactionId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), pluginProperties, requestOptions);
+        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
     }
 
     @Test(groups = "slow")
@@ -476,25 +480,25 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
 
         final PaymentTransaction completeTransactionByPaymentIdAndInvalidTransactionExternalKey = new PaymentTransaction();
         completeTransactionByPaymentIdAndInvalidTransactionExternalKey.setPaymentId(initialPayment.getPaymentId());
         completeTransactionByPaymentIdAndInvalidTransactionExternalKey.setTransactionExternalKey("bozo");
         try {
-            killBillClient.completePayment(completeTransactionByPaymentIdAndInvalidTransactionExternalKey, pluginProperties, requestOptions);
-            fail("Payment completion should fail when invalid transaction externalKey has been provided" );
+            paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentIdAndInvalidTransactionExternalKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            fail("Payment completion should fail when invalid transaction externalKey has been provided");
         } catch (final KillBillClientException expected) {
         }
 
         final PaymentTransaction completeTransactionByPaymentIdAndTransactionExternalKey = new PaymentTransaction();
-        completeTransactionByPaymentIdAndTransactionExternalKey.setPaymentId(initialPayment.getPaymentId());
+        completeTransactionByPaymentIdAndTransactionExternalKey.setPaymentExternalKey(paymentExternalKey);
         completeTransactionByPaymentIdAndTransactionExternalKey.setTransactionExternalKey(authTransactionExternalKey);
-        final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionByPaymentIdAndTransactionExternalKey, pluginProperties, requestOptions);
-        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), TransactionStatus.SUCCESS.name(), amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+        paymentApi.completeTransactionByExternalKey(completeTransactionByPaymentIdAndTransactionExternalKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
     }
 
-
     @Test(groups = "slow")
     public void testAuthorizeCompletionUsingPaymentIdAndTransactionType() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
@@ -510,23 +514,23 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
-
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
 
         final PaymentTransaction completeTransactionByPaymentIdAndInvalidTransactionType = new PaymentTransaction();
         completeTransactionByPaymentIdAndInvalidTransactionType.setPaymentId(initialPayment.getPaymentId());
-        completeTransactionByPaymentIdAndInvalidTransactionType.setTransactionType(TransactionType.CAPTURE.name());
+        completeTransactionByPaymentIdAndInvalidTransactionType.setTransactionType(TransactionType.CAPTURE);
         try {
-            killBillClient.completePayment(completeTransactionByPaymentIdAndInvalidTransactionType, pluginProperties, requestOptions);
-            fail("Payment completion should fail when invalid transaction type has been provided" );
+            paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentIdAndInvalidTransactionType,NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+            fail("Payment completion should fail when invalid transaction type has been provided");
         } catch (final KillBillClientException expected) {
         }
 
         final PaymentTransaction completeTransactionByPaymentIdAndTransactionType = new PaymentTransaction();
         completeTransactionByPaymentIdAndTransactionType.setPaymentId(initialPayment.getPaymentId());
-        completeTransactionByPaymentIdAndTransactionType.setTransactionType(transactionType.name());
-        final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionByPaymentIdAndTransactionType, pluginProperties, requestOptions);
-        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), TransactionStatus.SUCCESS.name(), amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+        completeTransactionByPaymentIdAndTransactionType.setTransactionType(transactionType);
+        paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentIdAndTransactionType, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
     }
 
     @Test(groups = "slow")
@@ -545,16 +549,16 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, pending, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.PENDING, amount, BigDecimal.ZERO, pendingPluginProperties, 1);
 
         final PaymentTransaction completeTransactionWithTypeAndKey = new PaymentTransaction();
-        completeTransactionWithTypeAndKey.setPaymentId(initialPayment.getPaymentId());
+        completeTransactionWithTypeAndKey.setPaymentExternalKey(paymentExternalKey);
         completeTransactionWithTypeAndKey.setTransactionExternalKey(authTransactionExternalKey);
-        final Payment completedPaymentByPaymentId = killBillClient.completePayment(completeTransactionWithTypeAndKey, pluginProperties, requestOptions);
-        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType.toString(), TransactionStatus.SUCCESS.name(), amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+        paymentApi.completeTransactionByExternalKey(completeTransactionWithTypeAndKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByPaymentId = paymentApi.getPayment(initialPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, completedPaymentByPaymentId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
     }
 
-
     @Test(groups = "slow")
     public void testAuthorizeInvalidCompletionUsingPaymentId() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
@@ -567,15 +571,14 @@ public class TestPayment extends TestJaxrsBase {
         final String paymentExternalKey = UUID.randomUUID().toString();
         final String authTransactionExternalKey = UUID.randomUUID().toString();
 
-        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS.name(), amount, amount, pluginProperties, 1);
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS, amount, amount, pluginProperties, 1);
 
         // The payment was already completed, it should succeed (no-op)
         final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
         completeTransactionByPaymentId.setPaymentId(initialPayment.getPaymentId());
-        killBillClient.completePayment(completeTransactionByPaymentId, pluginProperties, requestOptions);
+        paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
     }
 
-
     @Test(groups = "slow")
     public void testCompletionForSubsequentTransaction() throws Exception {
         final Account account = createAccountWithDefaultPaymentMethod();
@@ -586,7 +589,7 @@ public class TestPayment extends TestJaxrsBase {
 
         // Create a successful purchase
         final Payment authPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, purchaseTransactionExternalKey, TransactionType.PURCHASE,
-                                                            "SUCCESS", purchaseAmount, BigDecimal.ZERO, ImmutableMap.<String, String>of(), 1);
+                                                            TransactionStatus.SUCCESS, purchaseAmount, BigDecimal.ZERO, ImmutableMap.<String, String>of(), 1);
 
         final String pending = PaymentPluginStatus.PENDING.toString();
         final ImmutableMap<String, String> pluginProperties = ImmutableMap.<String, String>of(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, pending);
@@ -598,21 +601,22 @@ public class TestPayment extends TestJaxrsBase {
         refundTransaction.setTransactionExternalKey(refundTransactionExternalKey);
         refundTransaction.setAmount(purchaseAmount);
         refundTransaction.setCurrency(authPayment.getCurrency());
-        final Payment refundPayment = killBillClient.refundPayment(refundTransaction, null, pluginProperties, requestOptions);
+        final Payment refundPayment = paymentApi.refundPayment(authPayment.getPaymentId(), refundTransaction, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
         verifyPaymentWithPendingRefund(account, paymentMethodId, paymentExternalKey, purchaseTransactionExternalKey, purchaseAmount, refundTransactionExternalKey, refundPayment);
 
-
         final PaymentTransaction completeTransactionWithTypeAndKey = new PaymentTransaction();
-        completeTransactionWithTypeAndKey.setPaymentId(refundPayment.getPaymentId());
+        completeTransactionWithTypeAndKey.setPaymentExternalKey(paymentExternalKey);
         completeTransactionWithTypeAndKey.setTransactionExternalKey(refundTransactionExternalKey);
-        final Payment completedPaymentByTypeAndKey = killBillClient.completePayment(completeTransactionWithTypeAndKey, pluginProperties, requestOptions);
+        paymentApi.completeTransactionByExternalKey(completeTransactionWithTypeAndKey, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByTypeAndKey = paymentApi.getPayment(refundPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyPaymentWithPendingRefund(account, paymentMethodId, paymentExternalKey, purchaseTransactionExternalKey, purchaseAmount, refundTransactionExternalKey, completedPaymentByTypeAndKey);
 
         // Also, it should work if we specify the payment id and transaction id
         final PaymentTransaction completeTransactionWithTypeAndId = new PaymentTransaction();
         completeTransactionWithTypeAndId.setPaymentId(refundPayment.getPaymentId());
         completeTransactionWithTypeAndId.setTransactionId(refundPayment.getTransactions().get(1).getTransactionId());
-        final Payment completedPaymentByTypeAndId = killBillClient.completePayment(completeTransactionWithTypeAndId, pluginProperties, requestOptions);
+        paymentApi.completeTransaction(refundPayment.getPaymentId(), completeTransactionWithTypeAndId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
+        final Payment completedPaymentByTypeAndId = paymentApi.getPayment(refundPayment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyPaymentWithPendingRefund(account, paymentMethodId, paymentExternalKey, purchaseTransactionExternalKey, purchaseAmount, refundTransactionExternalKey, completedPaymentByTypeAndId);
     }
 
@@ -624,14 +628,18 @@ public class TestPayment extends TestJaxrsBase {
 
         final ComboPaymentTransaction comboPaymentTransaction = createComboPaymentTransaction(accountJson, paymentExternalKey);
 
-        final Payment payment = killBillClient.createPayment(comboPaymentTransaction, ImmutableMap.<String, String>of(), requestOptions);
+        final Payment payment = paymentApi.createComboPayment(comboPaymentTransaction, NULL_PLUGIN_NAMES, requestOptions);
         verifyComboPayment(payment, paymentExternalKey, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
 
         // Void payment using externalKey
         final String voidTransactionExternalKey = UUID.randomUUID().toString();
-        final Payment voidPayment = killBillClient.voidPayment(null, paymentExternalKey, voidTransactionExternalKey, null, ImmutableMap.<String, String>of(), requestOptions);
+        PaymentTransaction voidTransaction = new PaymentTransaction();
+        voidTransaction.setTransactionExternalKey(voidTransactionExternalKey);
+        voidTransaction.setPaymentExternalKey(paymentExternalKey);
+        paymentApi.voidPaymentByExternalKey(voidTransaction, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        final Payment voidPayment = paymentApi.getPayment(payment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         verifyPaymentTransaction(accountJson, voidPayment.getPaymentId(), paymentExternalKey, voidPayment.getTransactions().get(1),
-                                 voidTransactionExternalKey, null, "VOID", "SUCCESS");
+                                 voidTransactionExternalKey, null, TransactionType.VOID, TransactionStatus.SUCCESS);
     }
 
     @Test(groups = "slow")
@@ -643,7 +651,7 @@ public class TestPayment extends TestJaxrsBase {
 
         mockPaymentControlProviderPlugin.setAborted(true);
         try {
-            killBillClient.createPayment(comboPaymentTransaction, Arrays.asList(MockPaymentControlProviderPlugin.PLUGIN_NAME), ImmutableMap.<String, String>of(), requestOptions);
+            paymentApi.createComboPayment(comboPaymentTransaction, Arrays.asList(MockPaymentControlProviderPlugin.PLUGIN_NAME), requestOptions);
             fail();
         } catch (KillBillClientException e) {
             assertEquals(e.getResponse().getStatusCode(), 422);
@@ -666,13 +674,16 @@ public class TestPayment extends TestJaxrsBase {
         final PaymentTransaction authTransactionJson = new PaymentTransaction();
         authTransactionJson.setPaymentExternalKey(paymentExternalKey);
         authTransactionJson.setAmount(BigDecimal.TEN);
-        authTransactionJson.setTransactionType("AUTHORIZE");
-        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction(accountJson, null, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of());
+        authTransactionJson.setTransactionType(TransactionType.AUTHORIZE);
+        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction();
+        comboPaymentTransaction.setAccount(accountJson);
+        comboPaymentTransaction.setTransaction(authTransactionJson);
+        comboPaymentTransaction.setTransaction(authTransactionJson);
 
-        final Payment payment = killBillClient.createPayment(comboPaymentTransaction, ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), ImmutableMap.<String, String>of(), requestOptions);
+        final Payment payment = paymentApi.createComboPayment(comboPaymentTransaction, ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), requestOptions);
         verifyComboPayment(payment, paymentExternalKey, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
 
-        assertEquals(killBillClient.getPayment(payment.getPaymentId(), false, true, ImmutableMap.<String, String>of(), AuditLevel.NONE, requestOptions).getPaymentAttempts().size(), 1);
+        assertEquals(paymentApi.getPayment(payment.getPaymentId(), false, true, ImmutableMap.<String, String>of(), AuditLevel.NONE, requestOptions).getPaymentAttempts().size(), 1);
     }
 
     @Test(groups = "slow")
@@ -684,7 +695,7 @@ public class TestPayment extends TestJaxrsBase {
 
         mockPaymentControlProviderPlugin.throwsException(new IllegalStateException());
         try {
-            killBillClient.createPayment(comboPaymentTransaction, Arrays.asList(MockPaymentControlProviderPlugin.PLUGIN_NAME), ImmutableMap.<String, String>of(), requestOptions);
+            paymentApi.createComboPayment(comboPaymentTransaction, Arrays.asList(MockPaymentControlProviderPlugin.PLUGIN_NAME), requestOptions);
             fail();
         } catch (KillBillClientException e) {
             assertEquals(e.getResponse().getStatusCode(), 500);
@@ -696,7 +707,10 @@ public class TestPayment extends TestJaxrsBase {
         info.setProperties(null);
 
         final String paymentMethodExternalKey = UUID.randomUUID().toString();
-        final PaymentMethod paymentMethodJson = new PaymentMethod(null, paymentMethodExternalKey, null, true, PLUGIN_NAME, info);
+        final PaymentMethod paymentMethodJson = new PaymentMethod();
+        paymentMethodJson.setExternalKey(paymentMethodExternalKey);
+        paymentMethodJson.setPluginName(PLUGIN_NAME);
+        paymentMethodJson.setPluginInfo(info);
 
         final String authTransactionExternalKey = UUID.randomUUID().toString();
         final PaymentTransaction authTransactionJson = new PaymentTransaction();
@@ -704,9 +718,9 @@ public class TestPayment extends TestJaxrsBase {
         authTransactionJson.setCurrency(accountJson.getCurrency());
         authTransactionJson.setPaymentExternalKey(paymentExternalKey);
         authTransactionJson.setTransactionExternalKey(authTransactionExternalKey);
-        authTransactionJson.setTransactionType("AUTHORIZE");
+        authTransactionJson.setTransactionType(TransactionType.AUTHORIZE);
 
-        return new ComboPaymentTransaction(accountJson, paymentMethodJson, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of());
+        return new ComboPaymentTransaction(accountJson, paymentMethodJson, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of(), null);
     }
 
     @Test(groups = "slow")
@@ -718,11 +732,15 @@ public class TestPayment extends TestJaxrsBase {
         info.setProperties(null);
 
         final UUID paymentMethodId = UUID.randomUUID();
-        final PaymentMethod paymentMethodJson = new PaymentMethod(paymentMethodId, null, null, true, PLUGIN_NAME, info);
+        final PaymentMethod paymentMethodJson = new PaymentMethod();
+        paymentMethodJson.setPluginName(PLUGIN_NAME);
+        paymentMethodJson.setPluginInfo(info);
+        paymentMethodJson.setIsDefault(true);
+        paymentMethodJson.setPaymentMethodId(paymentMethodId);
 
-        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction(accountJson, paymentMethodJson, null, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of());
+        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction(accountJson, paymentMethodJson, new PaymentTransaction(), ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of(), null);
 
-        final Payment payment = killBillClient.createPayment(comboPaymentTransaction, ImmutableMap.<String, String>of(), requestOptions);
+        final Payment payment = paymentApi.createComboPayment(comboPaymentTransaction, NULL_PLUGIN_NAMES, requestOptions);
         // Client returns null in case of a 404
         Assert.assertNull(payment);
     }
@@ -731,20 +749,20 @@ public class TestPayment extends TestJaxrsBase {
     public void testGetTagsForPaymentTransaction() throws Exception {
         UUID tagDefinitionId = UUID.randomUUID();
         String tagDefinitionName = "payment-transaction";
-        TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        final TagDefinition createdTagDefinition = killBillClient.createTagDefinition(tagDefinition, requestOptions);
+        TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        final TagDefinition createdTagDefinition = tagDefinitionApi.createTagDefinition(tagDefinition, requestOptions);
 
         final Account account = createAccountWithDefaultPaymentMethod();
         final String externalPaymentKey = UUID.randomUUID().toString();
         final UUID paymentId = testCreateRetrievePayment(account, null, externalPaymentKey, 1);
 
-        final Payment payment = killBillClient.getPaymentByExternalKey(externalPaymentKey, requestOptions);
+        final Payment payment = paymentApi.getPaymentByExternalKey(externalPaymentKey, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(payment.getPaymentId(), paymentId);
 
         UUID paymentTransactionId = payment.getTransactions().get(0).getTransactionId();
-        killBillClient.createPaymentTransactionTag(paymentTransactionId, createdTagDefinition.getId(), requestOptions);
+        paymentTransactionApi.createTransactionTags(paymentTransactionId, ImmutableList.<UUID>of(createdTagDefinition.getId()), requestOptions);
 
-        final Tags paymentTransactionTags = killBillClient.getPaymentTransactionTags(paymentTransactionId, requestOptions);
+        final Tags paymentTransactionTags = paymentTransactionApi.getTransactionTags(paymentTransactionId, requestOptions);
 
         Assert.assertNotNull(paymentTransactionTags);
         Assert.assertEquals(paymentTransactionTags.get(0).getTagDefinitionName(), tagDefinitionName);
@@ -754,18 +772,18 @@ public class TestPayment extends TestJaxrsBase {
     public void testCreateTagForPaymentTransaction() throws Exception {
         UUID tagDefinitionId = UUID.randomUUID();
         String tagDefinitionName = "payment-transaction";
-        TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        final TagDefinition createdTagDefinition = killBillClient.createTagDefinition(tagDefinition, requestOptions);
+        TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        final TagDefinition createdTagDefinition = tagDefinitionApi.createTagDefinition(tagDefinition, requestOptions);
 
         final Account account = createAccountWithDefaultPaymentMethod();
         final String externalPaymentKey = UUID.randomUUID().toString();
         final UUID paymentId = testCreateRetrievePayment(account, null, externalPaymentKey, 1);
 
-        final Payment payment = killBillClient.getPaymentByExternalKey(externalPaymentKey, requestOptions);
+        final Payment payment = paymentApi.getPaymentByExternalKey(externalPaymentKey, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(payment.getPaymentId(), paymentId);
 
         UUID paymentTransactionId = payment.getTransactions().get(0).getTransactionId();
-        final Tags paymentTransactionTag = killBillClient.createPaymentTransactionTag(paymentTransactionId, createdTagDefinition.getId(), requestOptions);
+        final Tags paymentTransactionTag = paymentTransactionApi.createTransactionTags(paymentTransactionId, ImmutableList.<UUID>of(createdTagDefinition.getId()), requestOptions);
 
         Assert.assertNotNull(paymentTransactionTag);
         Assert.assertEquals(paymentTransactionTag.get(0).getTagDefinitionName(), tagDefinitionName);
@@ -776,11 +794,10 @@ public class TestPayment extends TestJaxrsBase {
         final Account account = createAccountWithDefaultPaymentMethod();
         final String externalPaymentKey = UUID.randomUUID().toString();
         final UUID paymentId = testCreateRetrievePayment(account, null, externalPaymentKey, 1);
-
-        final Payment payment = killBillClient.getPaymentByExternalKey(externalPaymentKey);
+        final Payment payment = paymentApi.getPaymentByExternalKey(externalPaymentKey, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(payment.getPaymentId(), paymentId);
 
-        final List<AuditLog> paymentAuditLogWithHistory = killBillClient.getPaymentAuditLogsWithHistory(account.getAccountId(), paymentId);
+        final List<AuditLog> paymentAuditLogWithHistory = paymentApi.getPaymentAuditLogsWithHistory(paymentId, requestOptions);
         assertEquals(paymentAuditLogWithHistory.size(), 8);
         assertEquals(paymentAuditLogWithHistory.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(paymentAuditLogWithHistory.get(0).getObjectType(), ObjectType.PAYMENT);
@@ -818,7 +835,7 @@ public class TestPayment extends TestJaxrsBase {
         // Authorization
         final String authTransactionExternalKey = UUID.randomUUID().toString();
         final Payment authPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, TransactionType.AUTHORIZE,
-                                                            "SUCCESS", BigDecimal.TEN, BigDecimal.TEN, ImmutableMap.<String, String>of(), paymentNb);
+                                                            TransactionStatus.SUCCESS, BigDecimal.TEN, BigDecimal.TEN, ImmutableMap.<String, String>of(), paymentNb);
 
         // Capture 1
         final String capture1TransactionExternalKey = UUID.randomUUID().toString();
@@ -829,22 +846,22 @@ public class TestPayment extends TestJaxrsBase {
         captureTransaction.setPaymentExternalKey(paymentExternalKey);
         captureTransaction.setTransactionExternalKey(capture1TransactionExternalKey);
         // captureAuthorization is using paymentId
-        final Payment capturedPayment1 = killBillClient.captureAuthorization(captureTransaction, requestOptions);
-        verifyPayment(account, paymentMethodId, capturedPayment1, paymentExternalKey, authTransactionExternalKey, "AUTHORIZE", "SUCCESS",
+        final Payment capturedPayment1 = paymentApi.captureAuthorization(authPayment.getPaymentId(), captureTransaction, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, capturedPayment1, paymentExternalKey, authTransactionExternalKey, TransactionType.AUTHORIZE, TransactionStatus.SUCCESS,
                       BigDecimal.TEN, BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ZERO, 2, paymentNb);
         verifyPaymentTransaction(account, authPayment.getPaymentId(), paymentExternalKey, capturedPayment1.getTransactions().get(1),
-                                 capture1TransactionExternalKey, captureTransaction.getAmount(), "CAPTURE", "SUCCESS");
+                                 capture1TransactionExternalKey, captureTransaction.getAmount(), TransactionType.CAPTURE, TransactionStatus.SUCCESS);
 
         // Capture 2
         final String capture2TransactionExternalKey = UUID.randomUUID().toString();
         captureTransaction.setTransactionExternalKey(capture2TransactionExternalKey);
         // captureAuthorization is using externalKey
         captureTransaction.setPaymentId(null);
-        final Payment capturedPayment2 = killBillClient.captureAuthorization(captureTransaction, requestOptions);
-        verifyPayment(account, paymentMethodId, capturedPayment2, paymentExternalKey, authTransactionExternalKey, "AUTHORIZE", "SUCCESS",
+        final Payment capturedPayment2 = paymentApi.captureAuthorizationByExternalKey(captureTransaction, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, capturedPayment2, paymentExternalKey, authTransactionExternalKey, TransactionType.AUTHORIZE, TransactionStatus.SUCCESS,
                       BigDecimal.TEN, BigDecimal.TEN, new BigDecimal("2"), BigDecimal.ZERO, 3, paymentNb);
         verifyPaymentTransaction(account, authPayment.getPaymentId(), paymentExternalKey, capturedPayment2.getTransactions().get(2),
-                                 capture2TransactionExternalKey, captureTransaction.getAmount(), "CAPTURE", "SUCCESS");
+                                 capture2TransactionExternalKey, captureTransaction.getAmount(), TransactionType.CAPTURE, TransactionStatus.SUCCESS);
 
         // Refund
         final String refundTransactionExternalKey = UUID.randomUUID().toString();
@@ -854,11 +871,11 @@ public class TestPayment extends TestJaxrsBase {
         refundTransaction.setCurrency(account.getCurrency());
         refundTransaction.setPaymentExternalKey(paymentExternalKey);
         refundTransaction.setTransactionExternalKey(refundTransactionExternalKey);
-        final Payment refundPayment = killBillClient.refundPayment(refundTransaction, requestOptions);
-        verifyPayment(account, paymentMethodId, refundPayment, paymentExternalKey, authTransactionExternalKey, "AUTHORIZE", "SUCCESS",
+        final Payment refundPayment = paymentApi.refundPayment(authPayment.getPaymentId(), refundTransaction, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+        verifyPayment(account, paymentMethodId, refundPayment, paymentExternalKey, authTransactionExternalKey, TransactionType.AUTHORIZE, TransactionStatus.SUCCESS,
                       BigDecimal.TEN, BigDecimal.TEN, new BigDecimal("2"), new BigDecimal("2"), 4, paymentNb);
         verifyPaymentTransaction(account, authPayment.getPaymentId(), paymentExternalKey, refundPayment.getTransactions().get(3),
-                                 refundTransactionExternalKey, refundTransaction.getAmount(), "REFUND", "SUCCESS");
+                                 refundTransactionExternalKey, refundTransaction.getAmount(), TransactionType.REFUND, TransactionStatus.SUCCESS);
 
         return authPayment.getPaymentId();
     }
@@ -868,7 +885,7 @@ public class TestPayment extends TestJaxrsBase {
                                             final String paymentExternalKey,
                                             final String transactionExternalKey,
                                             final TransactionType transactionType,
-                                            final String transactionStatus,
+                                            final TransactionStatus transactionStatus,
                                             final BigDecimal transactionAmount,
                                             final BigDecimal authAmount,
                                             final Map<String, String> pluginProperties,
@@ -878,10 +895,10 @@ public class TestPayment extends TestJaxrsBase {
         authTransaction.setCurrency(account.getCurrency());
         authTransaction.setPaymentExternalKey(paymentExternalKey);
         authTransaction.setTransactionExternalKey(transactionExternalKey);
-        authTransaction.setTransactionType(transactionType.toString());
-        final Payment payment = killBillClient.createPayment(account.getAccountId(), paymentMethodId, authTransaction, pluginProperties, requestOptions);
+        authTransaction.setTransactionType(transactionType);
+        final Payment payment = accountApi.processPayment(account.getAccountId(), authTransaction, paymentMethodId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
 
-        verifyPayment(account, paymentMethodId, payment, paymentExternalKey, transactionExternalKey, transactionType.toString(), transactionStatus, transactionAmount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
+        verifyPayment(account, paymentMethodId, payment, paymentExternalKey, transactionExternalKey, transactionType, transactionStatus, transactionAmount, authAmount, BigDecimal.ZERO, BigDecimal.ZERO, 1, paymentNb);
 
         return payment;
     }
@@ -900,7 +917,7 @@ public class TestPayment extends TestJaxrsBase {
         assertEquals(payment.getRefundedAmount().compareTo(refundedAmount), 0);
         assertEquals(payment.getTransactions().size(), nbTransactions);
 
-        final Payments Payments = killBillClient.getPayments(requestOptions);
+        final Payments Payments = paymentApi.getPayments(null, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(Payments.size(), paymentNb);
         assertEquals(Payments.get(paymentNb - 1), payment);
     }
@@ -910,8 +927,8 @@ public class TestPayment extends TestJaxrsBase {
                                final Payment payment,
                                final String paymentExternalKey,
                                final String firstTransactionExternalKey,
-                               final String firstTransactionType,
-                               final String firstTransactionStatus,
+                               final TransactionType firstTransactionType,
+                               final TransactionStatus firstTransactionStatus,
                                final BigDecimal firstTransactionAmount,
                                final BigDecimal paymentAuthAmount,
                                final BigDecimal capturedAmount,
@@ -942,14 +959,14 @@ public class TestPayment extends TestJaxrsBase {
         assertEquals(payment.getCurrency(), account.getCurrency());
         assertEquals(payment.getTransactions().size(), nbTransactions);
 
-        final Payments Payments = killBillClient.getPayments();
+        final Payments Payments = paymentApi.getPayments(null, NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(Payments.size(), paymentNb);
         assertEquals(Payments.get(paymentNb - 1), payment);
 
-        final Payment retrievedPayment = killBillClient.getPayment(payment.getPaymentId());
+        final Payment retrievedPayment = paymentApi.getPayment(payment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(retrievedPayment, payment);
 
-        final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(account.getAccountId());
+        final Payments paymentsForAccount = accountApi.getPaymentsForAccount(account.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         assertEquals(paymentsForAccount.size(), paymentNb);
         assertEquals(paymentsForAccount.get(paymentNb - 1), payment);
     }
@@ -960,8 +977,8 @@ public class TestPayment extends TestJaxrsBase {
                                           final PaymentTransaction paymentTransaction,
                                           final String transactionExternalKey,
                                           @Nullable final BigDecimal amount,
-                                          final String transactionType,
-                                          final String transactionStatus) {
+                                          final TransactionType transactionType,
+                                          final TransactionStatus transactionStatus) {
         assertEquals(paymentTransaction.getPaymentId(), paymentId);
         Assert.assertNotNull(paymentTransaction.getTransactionId());
         assertEquals(paymentTransaction.getTransactionType(), transactionType);
@@ -978,7 +995,7 @@ public class TestPayment extends TestJaxrsBase {
     }
 
     private void verifyPaymentWithPendingRefund(final Account account, final UUID paymentMethodId, final String paymentExternalKey, final String authTransactionExternalKey, final BigDecimal purchaseAmount, final String refundTransactionExternalKey, final Payment refundPayment) throws KillBillClientException {
-        verifyPayment(account, paymentMethodId, refundPayment, paymentExternalKey, authTransactionExternalKey, "PURCHASE", "SUCCESS", purchaseAmount, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, 2, 1);
-        verifyPaymentTransaction(account, refundPayment.getPaymentId(), paymentExternalKey, refundPayment.getTransactions().get(1), refundTransactionExternalKey, purchaseAmount, "REFUND", "PENDING");
+        verifyPayment(account, paymentMethodId, refundPayment, paymentExternalKey, authTransactionExternalKey, TransactionType.PURCHASE, TransactionStatus.SUCCESS, purchaseAmount, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, 2, 1);
+        verifyPaymentTransaction(account, refundPayment.getPaymentId(), paymentExternalKey, refundPayment.getTransactions().get(1), refundTransactionExternalKey, purchaseAmount, TransactionType.REFUND, TransactionStatus.PENDING);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentGateway.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentGateway.java
index 5c87db5..5238c5e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentGateway.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentGateway.java
@@ -19,20 +19,17 @@ package org.killbill.billing.jaxrs;
 
 import java.util.UUID;
 
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.ComboHostedPaymentPage;
-import org.killbill.billing.client.model.HostedPaymentPageFields;
-import org.killbill.billing.client.model.HostedPaymentPageFormDescriptor;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
-import org.killbill.billing.client.model.PluginProperty;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.ComboHostedPaymentPage;
+import org.killbill.billing.client.model.gen.HostedPaymentPageFields;
+import org.killbill.billing.client.model.gen.HostedPaymentPageFormDescriptor;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.gen.PluginProperty;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.ning.http.client.Response;
-
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 
 public class TestPaymentGateway extends TestJaxrsBase {
 
@@ -42,7 +39,7 @@ public class TestPaymentGateway extends TestJaxrsBase {
 
         final HostedPaymentPageFields hppFields = new HostedPaymentPageFields();
 
-        final HostedPaymentPageFormDescriptor hostedPaymentPageFormDescriptor = killBillClient.buildFormDescriptor(hppFields, account.getAccountId(), null, ImmutableMap.<String, String>of(), requestOptions);
+        final HostedPaymentPageFormDescriptor hostedPaymentPageFormDescriptor = paymentGatewayApi.buildFormDescriptor(account.getAccountId(), hppFields, null, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(hostedPaymentPageFormDescriptor.getKbAccountId(), account.getAccountId());
     }
 
@@ -52,19 +49,18 @@ public class TestPaymentGateway extends TestJaxrsBase {
         account.setAccountId(null);
 
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
-        final PaymentMethod paymentMethod = new PaymentMethod(null, UUID.randomUUID().toString(), null, true, PLUGIN_NAME, info);
+        final PaymentMethod paymentMethod = new PaymentMethod(null, UUID.randomUUID().toString(), null, true, PLUGIN_NAME, info, null);
 
         final HostedPaymentPageFields hppFields = new HostedPaymentPageFields();
 
-        final ComboHostedPaymentPage comboHostedPaymentPage = new ComboHostedPaymentPage(account, paymentMethod, ImmutableList.<PluginProperty>of(), hppFields);
+        final ComboHostedPaymentPage comboHostedPaymentPage = new ComboHostedPaymentPage(account, paymentMethod, hppFields, ImmutableList.<PluginProperty>of(), null);
 
-        final HostedPaymentPageFormDescriptor hostedPaymentPageFormDescriptor = killBillClient.buildFormDescriptor(comboHostedPaymentPage, ImmutableMap.<String, String>of(), requestOptions);
+        final HostedPaymentPageFormDescriptor hostedPaymentPageFormDescriptor = paymentGatewayApi.buildComboFormDescriptor(comboHostedPaymentPage, NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertNotNull(hostedPaymentPageFormDescriptor.getKbAccountId());
     }
 
     @Test(groups = "slow")
     public void testProcessNotification() throws Exception {
-        final Response response = killBillClient.processNotification("TOTO", PLUGIN_NAME, ImmutableMap.<String, String>of(), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 200);
+        paymentGatewayApi.processNotification(PLUGIN_NAME, "TOTO", NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentMethod.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentMethod.java
index c2e6dc9..df9559c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentMethod.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentMethod.java
@@ -25,13 +25,13 @@ import java.util.List;
 import java.util.UUID;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.CustomField;
 import org.killbill.billing.client.model.CustomFields;
-import org.killbill.billing.client.model.PaymentMethod;
 import org.killbill.billing.client.model.PaymentMethods;
-import org.killbill.billing.client.model.PluginProperty;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.CustomField;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PluginProperty;
 import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.audit.ChangeType;
 import org.testng.Assert;
@@ -47,20 +47,20 @@ public class TestPaymentMethod extends TestJaxrsBase {
 
         final Account accountJson = createAccountWithDefaultPaymentMethod("foo");
 
-        final PaymentMethod paymentMethodJson1 = killBillClient.getPaymentMethodByKey("foo", true);
+        final PaymentMethod paymentMethodJson1 = paymentMethodApi.getPaymentMethodByKey("foo", NULL_PLUGIN_PROPERTIES, requestOptions);
 
-        final PaymentMethod paymentMethodJson2 = killBillClient.getPaymentMethod(accountJson.getPaymentMethodId(), true);
+        final PaymentMethod paymentMethodJson2 = paymentMethodApi.getPaymentMethod(accountJson.getPaymentMethodId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(paymentMethodJson1, paymentMethodJson2);
 
-        final PaymentMethod paymentMethodJson3 = killBillClient.getPaymentMethodByKey("doesnotexist", true);
+        final PaymentMethod paymentMethodJson3 = paymentMethodApi.getPaymentMethodByKey("doesnotexist", NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertNull(paymentMethodJson3);
     }
 
     @Test(groups = "slow", description = "Can search payment methods")
     public void testSearchPaymentMethods() throws Exception {
         // Search random key
-        Assert.assertEquals(killBillClient.searchPaymentMethodsByKey(UUID.randomUUID().toString()).size(), 0);
-        Assert.assertEquals(killBillClient.searchPaymentMethodsByKeyAndPlugin(UUID.randomUUID().toString(), PLUGIN_NAME).size(), 0);
+        Assert.assertEquals(paymentMethodApi.searchPaymentMethods(UUID.randomUUID().toString(), null, NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
+        Assert.assertEquals(paymentMethodApi.searchPaymentMethods(UUID.randomUUID().toString(), PLUGIN_NAME, NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
 
         // Create a payment method
         final List<PluginProperty> pmProperties = new ArrayList<PluginProperty>();
@@ -71,11 +71,11 @@ public class TestPaymentMethod extends TestJaxrsBase {
         pmProperties.add(new PluginProperty("CC_COUNTRY", "Zimbawe", false));
 
         final Account accountJson = createAccountWithDefaultPaymentMethod(UUID.randomUUID().toString(), pmProperties);
-        final PaymentMethod paymentMethodJson = killBillClient.getPaymentMethod(accountJson.getPaymentMethodId(), true);
+        final PaymentMethod paymentMethodJson = paymentMethodApi.getPaymentMethod(accountJson.getPaymentMethodId(), false, true, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
 
         // Search random key again
-        Assert.assertEquals(killBillClient.searchPaymentMethodsByKey(UUID.randomUUID().toString()).size(), 0);
-        Assert.assertEquals(killBillClient.searchPaymentMethodsByKeyAndPlugin(UUID.randomUUID().toString(), PLUGIN_NAME).size(), 0);
+        Assert.assertEquals(paymentMethodApi.searchPaymentMethods(UUID.randomUUID().toString(), null, NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
+        Assert.assertEquals(paymentMethodApi.searchPaymentMethods(UUID.randomUUID().toString(), PLUGIN_NAME, NULL_PLUGIN_PROPERTIES, requestOptions).size(), 0);
 
         // Last 4
         doSearch("4365", paymentMethodJson);
@@ -95,10 +95,10 @@ public class TestPaymentMethod extends TestJaxrsBase {
             createAccountWithDefaultPaymentMethod();
         }
 
-        final PaymentMethods allPaymentMethods = killBillClient.getPaymentMethods();
+        final PaymentMethods allPaymentMethods = paymentMethodApi.getPaymentMethods(null, NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(allPaymentMethods.size(), 5);
 
-        PaymentMethods page = killBillClient.getPaymentMethods(0L, 1L);
+        PaymentMethods page = paymentMethodApi.getPaymentMethods(0L, 1L, null, false, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
@@ -118,9 +118,11 @@ public class TestPaymentMethod extends TestJaxrsBase {
         customField.setObjectType(ObjectType.PAYMENT_METHOD);
         customField.setName("testKey");
         customField.setValue("testValue");
+        final CustomFields body = new CustomFields();
+        body.add(customField);
 
         // Create custom field
-        final CustomFields createdCustomFields = killBillClient.createPaymentMethodCustomField(paymentMethodId, customField, createdBy, reason, comment);
+        final CustomFields createdCustomFields = paymentMethodApi.createPaymentMethodCustomFields(paymentMethodId, body, requestOptions);
         Assert.assertEquals(createdCustomFields.size(), 1);
         final CustomField createdCustomField = createdCustomFields.get(0);
         Assert.assertEquals(createdCustomField.getName(), "testKey");
@@ -129,7 +131,7 @@ public class TestPaymentMethod extends TestJaxrsBase {
         Assert.assertEquals(createdCustomField.getObjectType(), ObjectType.PAYMENT_METHOD);
 
         // Retrieve custom field
-        final CustomFields retrievedCustomFields = killBillClient.getPaymentMethodCustomFields(paymentMethodId, AuditLevel.NONE);
+        final CustomFields retrievedCustomFields = paymentMethodApi.getPaymentMethodCustomFields(paymentMethodId, requestOptions);
         Assert.assertEquals(retrievedCustomFields.size(), 1);
         final CustomField retrievedCustomField = retrievedCustomFields.get(0);
         Assert.assertEquals(retrievedCustomField.getName(), "testKey");
@@ -138,8 +140,8 @@ public class TestPaymentMethod extends TestJaxrsBase {
         Assert.assertEquals(retrievedCustomField.getObjectType(), ObjectType.PAYMENT_METHOD);
 
         // Delete custom field
-        killBillClient.deletePaymentMethodCustomFields(paymentMethodId, Collections.<UUID>singletonList(createdCustomField.getCustomFieldId()), createdBy, reason, comment);
-        final CustomFields deletedCustomFields = killBillClient.getPaymentMethodCustomFields(paymentMethodId, AuditLevel.NONE);
+        paymentMethodApi.deletePaymentMethodCustomFields(paymentMethodId, Collections.<UUID>singletonList(createdCustomField.getCustomFieldId()), requestOptions);
+        final CustomFields deletedCustomFields = paymentMethodApi.getPaymentMethodCustomFields(paymentMethodId, requestOptions);
         Assert.assertEquals(deletedCustomFields.size(), 0);
     }
 
@@ -148,8 +150,7 @@ public class TestPaymentMethod extends TestJaxrsBase {
         final Account account = createAccountWithDefaultPaymentMethod();
         assertNotNull(account);
         final UUID paymentMethodId = account.getPaymentMethodId();
-
-        final List<AuditLog> paymentMethodAuditLogWithHistory = killBillClient.getPaymentMethodAuditLogsWithHistory(account.getAccountId(), paymentMethodId);
+        final List<AuditLog> paymentMethodAuditLogWithHistory = paymentMethodApi.getPaymentMethodAuditLogsWithHistory(paymentMethodId, requestOptions);
         assertEquals(paymentMethodAuditLogWithHistory.size(), 1);
         assertEquals(paymentMethodAuditLogWithHistory.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(paymentMethodAuditLogWithHistory.get(0).getObjectType(), ObjectType.PAYMENT_METHOD);
@@ -158,15 +159,14 @@ public class TestPaymentMethod extends TestJaxrsBase {
         final LinkedHashMap history1 = (LinkedHashMap) paymentMethodAuditLogWithHistory.get(0).getHistory();
         assertNotNull(history1);
         assertEquals(history1.get("accountId"), account.getAccountId().toString());
-
     }
 
     private void doSearch(final String searchKey, final PaymentMethod paymentMethodJson) throws Exception {
-        final List<PaymentMethod> results1 = killBillClient.searchPaymentMethodsByKey(searchKey, true);
+        final List<PaymentMethod> results1 = paymentMethodApi.searchPaymentMethods(searchKey, 0L, 100L, null, true, NULL_PLUGIN_PROPERTIES,  AuditLevel.NONE,  requestOptions);
         Assert.assertEquals(results1.size(), 1);
         Assert.assertEquals(results1.get(0), paymentMethodJson);
 
-        final List<PaymentMethod> results2 = killBillClient.searchPaymentMethodsByKeyAndPlugin(searchKey, PLUGIN_NAME);
+        final List<PaymentMethod> results2 = paymentMethodApi.searchPaymentMethods(searchKey, 0L, 100L, PLUGIN_NAME, true, NULL_PLUGIN_PROPERTIES, AuditLevel.NONE, requestOptions);
         Assert.assertEquals(results2.size(), 1);
         Assert.assertEquals(results2.get(0), paymentMethodJson);
     }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
index 9904585..de0326c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
@@ -29,10 +29,10 @@ import javax.annotation.Nullable;
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.KillBillHttpClient;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentTransaction;
-import org.killbill.billing.client.model.PluginProperty;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.PluginProperty;
 import org.killbill.billing.control.plugin.api.OnFailurePaymentControlResult;
 import org.killbill.billing.control.plugin.api.OnSuccessPaymentControlResult;
 import org.killbill.billing.control.plugin.api.PaymentControlApiException;
@@ -101,7 +101,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
 
         private void assertPluginProperties(final Iterable<org.killbill.billing.payment.api.PluginProperty> properties) {
             for (org.killbill.billing.payment.api.PluginProperty input : properties) {
-                boolean found  = false;
+                boolean found = false;
                 for (org.killbill.billing.payment.api.PluginProperty expect : expectedProperties) {
                     if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(input.getValue())) {
                         found = true;
@@ -112,7 +112,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
             }
 
             for (org.killbill.billing.payment.api.PluginProperty expect : expectedProperties) {
-                boolean found  = false;
+                boolean found = false;
                 for (org.killbill.billing.payment.api.PluginProperty input : properties) {
                     if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(input.getValue())) {
                         found = true;
@@ -237,7 +237,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
         final RequestOptions requestOptionsWithParams = basicRequestOptions.extend()
                                                                            .withQueryParams(params).build();
 
-        killBillClient.completePayment(completeTransactionByPaymentId, queryProperties, requestOptionsWithParams);
+        paymentApi.completeTransaction(initialPayment.getPaymentId(), completeTransactionByPaymentId, NULL_PLUGIN_NAMES, queryProperties, requestOptionsWithParams);
 
         //Capture the payment
         final PaymentTransaction captureTransaction = new PaymentTransaction();
@@ -245,7 +245,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
         captureTransaction.setProperties(bodyProperties);
         captureTransaction.setAmount(BigDecimal.TEN);
         captureTransaction.setCurrency(account.getCurrency());
-        killBillClient.captureAuthorization(captureTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
+        paymentApi.captureAuthorization(initialPayment.getPaymentId(), captureTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
 
         //Refund the payment
         final PaymentTransaction refundTransaction = new PaymentTransaction();
@@ -253,7 +253,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
         refundTransaction.setProperties(bodyProperties);
         refundTransaction.setAmount(BigDecimal.TEN);
         refundTransaction.setCurrency(account.getCurrency());
-        killBillClient.refundPayment(refundTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
+        paymentApi.refundPayment(initialPayment.getPaymentId(), refundTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
     }
 
     private Payment createVerifyTransaction(final Account account,
@@ -268,8 +268,8 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
         authTransaction.setCurrency(account.getCurrency());
         authTransaction.setPaymentExternalKey(paymentExternalKey);
         authTransaction.setTransactionExternalKey(transactionExternalKey);
-        authTransaction.setTransactionType(transactionType.toString());
-        final Payment payment = killBillClient.createPayment(account.getAccountId(), paymentMethodId, authTransaction, pluginProperties, requestOptions);
+        authTransaction.setTransactionType(transactionType);
+        final Payment payment = accountApi.processPayment(account.getAccountId(), authTransaction, paymentMethodId, NULL_PLUGIN_NAMES, pluginProperties, requestOptions);
         return payment;
     }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
index cbe1e97..36e1233 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
@@ -19,9 +19,9 @@ package org.killbill.billing.jaxrs;
 
 import java.util.HashMap;
 
-import org.killbill.billing.client.model.Account;
 import org.killbill.billing.client.model.Payments;
-import org.killbill.billing.client.model.TenantKey;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.TenantKeyValue;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.TransactionStatus;
@@ -76,12 +76,12 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         final String perTenantConfig = mapper.writeValueAsString(perTenantProperties);
 
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        final TenantKey tenantKey = killBillClient.postConfigurationPropertiesForTenant(perTenantConfig, requestOptions);
+        final TenantKeyValue tenantKey = tenantApi.uploadPerTenantConfiguration(perTenantConfig, requestOptions);
         callbackServlet.assertListenerStatus();
 
         final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice(false);
 
-        final Payments payments = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
+        final Payments payments = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(payments.size(), 1);
         Assert.assertEquals(payments.get(0).getTransactions().size(), 1);
 
@@ -93,24 +93,24 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         // Now unregister special per tenant config and we the first retry occurs one day after (and still fails), it now sets a retry date of 8 days
         //
         callbackServlet.pushExpectedEvents(ExtBusEventType.TENANT_CONFIG_DELETION);
-        killBillClient.unregisterConfigurationForTenant(requestOptions);
+        tenantApi.deletePerTenantConfiguration(requestOptions);
         callbackServlet.assertListenerStatus();
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.INVOICE_PAYMENT_FAILED, ExtBusEventType.PAYMENT_FAILED);
         clock.addDays(1);
         callbackServlet.assertListenerStatus();
 
-        final Payments payments2 = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
+        final Payments payments2 = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(payments2.size(), 1);
         Assert.assertEquals(payments2.get(0).getTransactions().size(), 2);
-        Assert.assertEquals(payments2.get(0).getTransactions().get(0).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
-        Assert.assertEquals(payments2.get(0).getTransactions().get(1).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
+        Assert.assertEquals(payments2.get(0).getTransactions().get(0).getStatus(), TransactionStatus.PAYMENT_FAILURE);
+        Assert.assertEquals(payments2.get(0).getTransactions().get(1).getStatus(), TransactionStatus.PAYMENT_FAILURE);
 
         clock.addDays(1);
         callbackServlet.assertListenerStatus();
 
         // No retry with default config
-        final Payments payments3 = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
+        final Payments payments3 = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(payments3.size(), 1);
         Assert.assertEquals(payments3.get(0).getTransactions().size(), 2);
 
@@ -119,11 +119,11 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         clock.addDays(7);
         callbackServlet.assertListenerStatus();
 
-        final Payments payments4 = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
+        final Payments payments4 = accountApi.getPaymentsForAccount(accountJson.getAccountId(), NULL_PLUGIN_PROPERTIES, requestOptions);
         Assert.assertEquals(payments4.size(), 1);
         Assert.assertEquals(payments4.get(0).getTransactions().size(), 3);
-        Assert.assertEquals(payments4.get(0).getTransactions().get(0).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
-        Assert.assertEquals(payments4.get(0).getTransactions().get(1).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
-        Assert.assertEquals(payments4.get(0).getTransactions().get(2).getStatus(), TransactionStatus.SUCCESS.name());
+        Assert.assertEquals(payments4.get(0).getTransactions().get(0).getStatus(), TransactionStatus.PAYMENT_FAILURE);
+        Assert.assertEquals(payments4.get(0).getTransactions().get(1).getStatus(), TransactionStatus.PAYMENT_FAILURE);
+        Assert.assertEquals(payments4.get(0).getTransactions().get(2).getStatus(), TransactionStatus.SUCCESS);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPlugin.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPlugin.java
index 9a03015..8fd9966 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPlugin.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPlugin.java
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.killbill.billing.client.RequestOptions;
 import org.killbill.billing.osgi.http.DefaultServletRouter;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -36,6 +37,8 @@ import com.ning.http.client.Response;
 
 public class TestPlugin extends TestJaxrsBase {
 
+    private static final String PLUGIN_PATH = "/plugins/";
+
     private static final String TEST_PLUGIN_NAME = "test-osgi";
 
     private static final byte[] TEST_PLUGIN_RESPONSE_BYTES = new byte[]{0xC, 0x0, 0xF, 0xF, 0xE, 0xE};
@@ -73,22 +76,22 @@ public class TestPlugin extends TestJaxrsBase {
 
         // We don't test the output here as it is some Jetty specific HTML blurb
 
-        response = killBillClient.pluginGET(uri);
+        response = pluginGET(uri, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
 
-        response = killBillClient.pluginHEAD(uri);
+        response = pluginHEAD(uri, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
 
-        response = killBillClient.pluginPOST(uri, null);
+        response = pluginPOST(uri, null, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
 
-        response = killBillClient.pluginPUT(uri, null);
+        response = pluginPUT(uri, null, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
 
-        response = killBillClient.pluginDELETE(uri);
+        response = pluginDELETE(uri, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
 
-        response = killBillClient.pluginOPTIONS(uri);
+        response = pluginOPTIONS(uri, requestOptions);
         testAndResetAllMarkers(response, 404, null, false, false, false, false, false, false);
     }
 
@@ -97,22 +100,22 @@ public class TestPlugin extends TestJaxrsBase {
         final String uri = TEST_PLUGIN_NAME + "/somethingSomething";
         Response response;
 
-        response = killBillClient.pluginGET(uri);
+        response = pluginGET(uri, requestOptions);
         testAndResetAllMarkers(response, 200, new byte[]{}, false, false, false, false, false, false);
 
-        response = killBillClient.pluginHEAD(uri);
+        response = pluginHEAD(uri, requestOptions);
         testAndResetAllMarkers(response, 204, new byte[]{}, false, false, false, false, false, false);
 
-        response = killBillClient.pluginPOST(uri, null);
+        response = pluginPOST(uri, null, requestOptions);
         testAndResetAllMarkers(response, 200, new byte[]{}, false, false, false, false, false, false);
 
-        response = killBillClient.pluginPUT(uri, null);
+        response = pluginPUT(uri, null, requestOptions);
         testAndResetAllMarkers(response, 200, new byte[]{}, false, false, false, false, false, false);
 
-        response = killBillClient.pluginDELETE(uri);
+        response = pluginDELETE(uri, requestOptions);
         testAndResetAllMarkers(response, 200, new byte[]{}, false, false, false, false, false, false);
 
-        response = killBillClient.pluginOPTIONS(uri);
+        response = pluginOPTIONS(uri, requestOptions);
         testAndResetAllMarkers(response, 200, new byte[]{}, false, false, false, false, false, false);
     }
 
@@ -120,22 +123,22 @@ public class TestPlugin extends TestJaxrsBase {
     public void testPassRequestsToKnownPluginAndKnownPath() throws Exception {
         Response response;
 
-        response = killBillClient.pluginGET(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_GET_PATH);
+        response = pluginGET(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_GET_PATH, requestOptions);
         testAndResetAllMarkers(response, 230, TEST_PLUGIN_RESPONSE_BYTES, true, false, false, false, false, false);
 
-        response = killBillClient.pluginHEAD(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_HEAD_PATH);
+        response = pluginHEAD(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_HEAD_PATH, requestOptions);
         testAndResetAllMarkers(response, 204, new byte[]{}, false, true, false, false, false, false);
 
-        response = killBillClient.pluginPOST(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_POST_PATH, null);
+        response = pluginPOST(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_POST_PATH, null, requestOptions);
         testAndResetAllMarkers(response, 230, TEST_PLUGIN_RESPONSE_BYTES, false, false, true, false, false, false);
 
-        response = killBillClient.pluginPUT(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_PUT_PATH, null);
+        response = pluginPUT(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_PUT_PATH, null, requestOptions);
         testAndResetAllMarkers(response, 230, TEST_PLUGIN_RESPONSE_BYTES, false, false, false, true, false, false);
 
-        response = killBillClient.pluginDELETE(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_DELETE_PATH);
+        response = pluginDELETE(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_DELETE_PATH, requestOptions);
         testAndResetAllMarkers(response, 230, TEST_PLUGIN_RESPONSE_BYTES, false, false, false, false, true, false);
 
-        response = killBillClient.pluginOPTIONS(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_OPTIONS_PATH);
+        response = pluginOPTIONS(TEST_PLUGIN_NAME + "/" + TEST_PLUGIN_VALID_OPTIONS_PATH, requestOptions);
         testAndResetAllMarkers(response, 230, TEST_PLUGIN_RESPONSE_BYTES, false, false, false, false, false, true);
     }
 
@@ -170,6 +173,33 @@ public class TestPlugin extends TestJaxrsBase {
         requestOPTIONSMarker.set(false);
     }
 
+    //
+    // Plugin routing endpoints are not officially part of api (yet)
+    //
+    private Response pluginGET(final String uri, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doGet(PLUGIN_PATH + uri, inputOptions);
+    }
+
+    private Response pluginHEAD(final String uri, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doHead(PLUGIN_PATH + uri, inputOptions);
+    }
+
+    private Response pluginPOST(final String uri, @Nullable final String body, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doPost(PLUGIN_PATH + uri, body, inputOptions);
+    }
+
+    private Response pluginDELETE(final String uri, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doDelete(PLUGIN_PATH + uri, inputOptions);
+    }
+
+    private Response pluginPUT(final String uri, @Nullable final String body, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doPut(PLUGIN_PATH + uri, body, inputOptions);
+    }
+
+    private Response pluginOPTIONS(final String uri, final RequestOptions inputOptions) throws Exception {
+        return killBillHttpClient.doOptions(PLUGIN_PATH + uri, inputOptions);
+    }
+
     private void setupOSGIPlugin() {
         ((DefaultServletRouter) servletRouter).registerServiceFromPath(TEST_PLUGIN_NAME, new HttpServlet() {
             @Override
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
index 47e92ac..e9bd390 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
@@ -18,10 +18,11 @@
 
 package org.killbill.billing.jaxrs;
 
+import java.io.File;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
@@ -29,17 +30,15 @@ import javax.ws.rs.core.Response.Status;
 
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Permissions;
-import org.killbill.billing.client.model.RoleDefinition;
-import org.killbill.billing.client.model.UserRoles;
+import org.killbill.billing.client.model.gen.RoleDefinition;
+import org.killbill.billing.client.model.gen.UserRoles;
 import org.killbill.billing.security.Permission;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.ning.http.client.Response;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.io.Files;
 import com.google.common.io.Resources;
 
 public class TestSecurity extends TestJaxrsBase {
@@ -49,7 +48,7 @@ public class TestSecurity extends TestJaxrsBase {
         logout();
 
         try {
-            killBillClient.getPermissions();
+            securityApi.getCurrentUserPermissions(requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getResponse().getStatusCode(), Status.UNAUTHORIZED.getStatusCode());
@@ -73,12 +72,12 @@ public class TestSecurity extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testDynamicUserRolesAllCatalogPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqeqsdswe", "jsddsh763s", "allcatalog", ImmutableList.of("catalog:*","tenant_kvs:add"), true);
+        testDynamicUserRolesInternal("wqeqsdswe", "jsddsh763s", "allcatalog", ImmutableList.of("catalog:*", "tenant_kvs:add"), true);
     }
 
     @Test(groups = "slow")
     public void testDynamicUserRolesCorrectCatalogPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqeq23f6we", "jds5gh763s", "correctcatalog", ImmutableList.of("catalog:config_upload","tenant_kvs:add"), true);
+        testDynamicUserRolesInternal("wqeq23f6we", "jds5gh763s", "correctcatalog", ImmutableList.of("catalog:config_upload", "tenant_kvs:add"), true);
     }
 
     @Test(groups = "slow")
@@ -93,7 +92,7 @@ public class TestSecurity extends TestJaxrsBase {
         final String role = UUID.randomUUID().toString();
         testDynamicUserRolesInternal(username, password, role, ImmutableList.of(""), false);
 
-        final Permissions permissions = killBillClient.getPermissions(RequestOptions.builder().withUser(username).withPassword(password).build());
+        final List<String> permissions = securityApi.getCurrentUserPermissions(RequestOptions.builder().withUser(username).withPassword(password).build());
         Assert.assertEquals(permissions.size(), 0);
     }
 
@@ -108,13 +107,11 @@ public class TestSecurity extends TestJaxrsBase {
                 permissions.add(cur.toString());
             }
         }
-        Response response = killBillClient.addRoleDefinition(new RoleDefinition(roleDefinition, permissions), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addRoleDefinition(new RoleDefinition(roleDefinition, permissions), requestOptions);
 
         final String username = "candy";
         final String password = "lolipop";
-        response = killBillClient.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), requestOptions);
 
         // Now 'login' as new user (along with roles to make an API call requiring permissions), and check behavior
         logout();
@@ -122,7 +119,7 @@ public class TestSecurity extends TestJaxrsBase {
 
         boolean success = false;
         try {
-            killBillClient.addRoleDefinition(new RoleDefinition("dsfdsfds", ImmutableList.of("*")), createdBy, reason, comment);
+            securityApi.addRoleDefinition(new RoleDefinition("dsfdsfds", ImmutableList.of("*")), requestOptions);
             success = true;
         } catch (final Exception e) {
         } finally {
@@ -131,7 +128,7 @@ public class TestSecurity extends TestJaxrsBase {
 
         success = false;
         try {
-            killBillClient.addUserRoles(new UserRoles("sdsd", "sdsdsd", ImmutableList.of(roleDefinition)), createdBy, reason, comment);
+            securityApi.addUserRoles(new UserRoles("sdsd", "sdsdsd", ImmutableList.of(roleDefinition)), requestOptions);
             success = true;
         } catch (final Exception e) {
         } finally {
@@ -148,55 +145,49 @@ public class TestSecurity extends TestJaxrsBase {
         final String username = "GuanYu";
         final String password = "IamAGreatWarrior";
 
-        Response response = killBillClient.addRoleDefinition(new RoleDefinition(roleDefinition, ImmutableList.of(allPermissions)), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addRoleDefinition(new RoleDefinition(roleDefinition, ImmutableList.of(allPermissions)), requestOptions);
 
-        response = killBillClient.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), requestOptions);
 
         logout();
         login(username, password);
-        Permissions permissions =  killBillClient.getPermissions();
+        List<String> permissions = securityApi.getCurrentUserPermissions(requestOptions);
         Assert.assertEquals(permissions.size(), Permission.values().length);
 
         String newPassword = "IamTheBestWarrior";
-        killBillClient.updateUserPassword(username, newPassword, createdBy, reason, comment);
+        securityApi.updateUserPassword(username, new UserRoles(username, newPassword, null), requestOptions);
 
         logout();
         login(username, newPassword);
-        permissions =  killBillClient.getPermissions();
+        permissions = securityApi.getCurrentUserPermissions(requestOptions);
         Assert.assertEquals(permissions.size(), Permission.values().length);
 
         final String newRoleDefinition = "somethingLessNice";
         // Only enough permissions to invalidate itself in the last step...
         final String littlePermissions = "user";
 
-        response = killBillClient.addRoleDefinition(new RoleDefinition(newRoleDefinition, ImmutableList.of(littlePermissions)), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addRoleDefinition(new RoleDefinition(newRoleDefinition, ImmutableList.of(littlePermissions)), requestOptions);
 
-        killBillClient.updateUserRoles(username, ImmutableList.of(newRoleDefinition), createdBy, reason, comment);
-        permissions =  killBillClient.getPermissions();
+        securityApi.updateUserRoles(username, new UserRoles(username, null, ImmutableList.of(newRoleDefinition)), requestOptions);
+        permissions = securityApi.getCurrentUserPermissions(requestOptions);
         // This will only work if correct shiro cache invalidation was performed... requires lots of sweat to get it to work ;-)
         Assert.assertEquals(permissions.size(), 2);
 
-        killBillClient.invalidateUser(username, createdBy, reason, comment);
+        securityApi.invalidateUser(username, requestOptions);
         try {
-            killBillClient.getPermissions();
+            securityApi.getCurrentUserPermissions(requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getResponse().getStatusCode(), Status.UNAUTHORIZED.getStatusCode());
         }
 
-
     }
 
     private void testDynamicUserRolesInternal(final String username, final String password, final String roleDefinition, final List<String> permissions, final boolean expectPermissionSuccess) throws Exception {
 
-        Response response = killBillClient.addRoleDefinition(new RoleDefinition(roleDefinition, permissions), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addRoleDefinition(new RoleDefinition(roleDefinition, permissions), requestOptions);
 
-        response = killBillClient.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), createdBy, reason, comment);
-        Assert.assertEquals(response.getStatusCode(), 201);
+        securityApi.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), requestOptions);
 
         // Now 'login' as new user (along with roles to make an API call requiring permissions), and check behavior
         logout();
@@ -205,7 +196,9 @@ public class TestSecurity extends TestJaxrsBase {
         boolean success = false;
         try {
             final String catalogPath = Resources.getResource("SpyCarBasic.xml").getPath();
-            killBillClient.uploadXMLCatalog(catalogPath, createdBy, reason, comment);
+            final File catalogFile = new File(catalogPath);
+            final String body = Files.toString(catalogFile, Charset.forName("UTF-8"));
+            catalogApi.uploadCatalogXml(body, requestOptions);
             success = true;
         } catch (final Exception e) {
             if (expectPermissionSuccess ||
@@ -219,6 +212,6 @@ public class TestSecurity extends TestJaxrsBase {
 
     private List<String> getPermissions(@Nullable final String username, @Nullable final String password) throws Exception {
         login(username, password);
-        return killBillClient.getPermissions();
+        return securityApi.getCurrentUserPermissions(requestOptions);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
index a4142aa..2d494f5 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
@@ -29,12 +29,12 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.Subscription;
-import org.killbill.billing.client.model.Tag;
-import org.killbill.billing.client.model.TagDefinition;
 import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.AuditLog;
+import org.killbill.billing.client.model.gen.Subscription;
+import org.killbill.billing.client.model.gen.Tag;
+import org.killbill.billing.client.model.gen.TagDefinition;
 import org.killbill.billing.util.api.AuditLevel;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.tag.ControlTagType;
@@ -42,7 +42,11 @@ import org.killbill.billing.util.tag.dao.SystemTags;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.ning.http.util.UTF8UrlEncoder;
+
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -52,26 +56,24 @@ public class TestTag extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Cannot add badly formatted TagDefinition")
     public void testTagErrorHandling() throws Exception {
-        final TagDefinition[] tagDefinitions = {new TagDefinition(null, false, null, null,  ImmutableList.<ObjectType>of(ObjectType.ACCOUNT)),
-                                                new TagDefinition(null, false, "something", null,  ImmutableList.<ObjectType>of(ObjectType.INVOICE)),
-                                                new TagDefinition(null, false, null, "something",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION))};
+        final TagDefinition[] tagDefinitions = {new TagDefinition(null, false, null, null, ImmutableList.<ObjectType>of(ObjectType.ACCOUNT), null),
+                                                new TagDefinition(null, false, "something", null, ImmutableList.<ObjectType>of(ObjectType.INVOICE), null),
+                                                new TagDefinition(null, false, null, "something", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null)};
 
         for (final TagDefinition tagDefinition : tagDefinitions) {
             try {
-                killBillClient.createTagDefinition(tagDefinition, requestOptions);
+                tagDefinitionApi.createTagDefinition(tagDefinition, requestOptions);
                 fail();
             } catch (final KillBillClientException e) {
             }
         }
     }
 
-
-
     @Test(groups = "slow", description = "Can create a TagDefinition")
     public void testTagDefinitionOk() throws Exception {
-        final TagDefinition input = new TagDefinition(null, false, "blue", "relaxing color",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
+        final TagDefinition input = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
 
-        final TagDefinition objFromJson = killBillClient.createTagDefinition(input, requestOptions);
+        final TagDefinition objFromJson = tagDefinitionApi.createTagDefinition(input, requestOptions);
         assertNotNull(objFromJson);
         assertEquals(objFromJson.getName(), input.getName());
         assertEquals(objFromJson.getDescription(), input.getDescription());
@@ -79,34 +81,32 @@ public class TestTag extends TestJaxrsBase {
 
     @Test(groups = "slow", description = "Can create and delete TagDefinitions")
     public void testMultipleTagDefinitionOk() throws Exception {
-        List<TagDefinition> objFromJson = killBillClient.getTagDefinitions(requestOptions);
+        List<TagDefinition> objFromJson = tagDefinitionApi.getTagDefinitions(requestOptions);
         final int sizeSystemTag = objFromJson.isEmpty() ? 0 : objFromJson.size();
 
+        final TagDefinition inputBlue = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        tagDefinitionApi.createTagDefinition(inputBlue, requestOptions);
 
-        final TagDefinition inputBlue = new TagDefinition(null, false, "blue", "relaxing color",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        killBillClient.createTagDefinition(inputBlue, requestOptions);
+        final TagDefinition inputRed = new TagDefinition(null, false, "red", "hot color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        tagDefinitionApi.createTagDefinition(inputRed, requestOptions);
 
-        final TagDefinition inputRed = new TagDefinition(null, false, "red", "hot color",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        killBillClient.createTagDefinition(inputRed, requestOptions);
+        final TagDefinition inputYellow = new TagDefinition(null, false, "yellow", "vibrant color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        tagDefinitionApi.createTagDefinition(inputYellow, requestOptions);
 
-        final TagDefinition inputYellow = new TagDefinition(null, false, "yellow", "vibrant color",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        killBillClient.createTagDefinition(inputYellow, requestOptions);
+        final TagDefinition inputGreen = new TagDefinition(null, false, "green", "super relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        tagDefinitionApi.createTagDefinition(inputGreen, requestOptions);
 
-        final TagDefinition inputGreen = new TagDefinition(null, false, "green", "super relaxing color",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        killBillClient.createTagDefinition(inputGreen, requestOptions);
-
-        objFromJson = killBillClient.getTagDefinitions(requestOptions);
+        objFromJson = tagDefinitionApi.getTagDefinitions(requestOptions);
         assertNotNull(objFromJson);
         assertEquals(objFromJson.size(), 4 + sizeSystemTag);
 
-        killBillClient.deleteTagDefinition(objFromJson.get(0).getId(), requestOptions);
+        tagDefinitionApi.deleteTagDefinition(objFromJson.get(0).getId(), requestOptions);
 
-        objFromJson = killBillClient.getTagDefinitions(requestOptions);
+        objFromJson = tagDefinitionApi.getTagDefinitions(requestOptions);
         assertNotNull(objFromJson);
         assertEquals(objFromJson.size(), 3 + sizeSystemTag);
     }
 
-
     @Test(groups = "slow", description = "Can search all tags for an account")
     public void testGetAllTagsByType() throws Exception {
 
@@ -115,43 +115,43 @@ public class TestTag extends TestJaxrsBase {
 
         final Account account = createAccountWithDefaultPaymentMethod();
 
-        final Subscription subscriptionJson = createEntitlement(account.getAccountId(), "87544332", "Shotgun",
+        final Subscription subscriptionJson = createSubscription(account.getAccountId(), "87544332", "Shotgun",
                                                                 ProductCategory.BASE, BillingPeriod.MONTHLY, true);
 
         for (final ControlTagType controlTagType : ControlTagType.values()) {
-            killBillClient.createAccountTag(account.getAccountId(), controlTagType.getId(), requestOptions);
+            accountApi.createAccountTags(account.getAccountId(), ImmutableList.<UUID>of(controlTagType.getId()), requestOptions);
         }
 
-        final TagDefinition bundleTagDefInput = new TagDefinition(null, false, "bundletagdef", "nothing special",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        final TagDefinition bundleTagDef = killBillClient.createTagDefinition(bundleTagDefInput, requestOptions);
+        final TagDefinition bundleTagDefInput = new TagDefinition(null, false, "bundletagdef", "nothing special", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION), null);
+        final TagDefinition bundleTagDef = tagDefinitionApi.createTagDefinition(bundleTagDefInput, requestOptions);
 
-        killBillClient.createBundleTag(subscriptionJson.getBundleId(), bundleTagDef.getId(), requestOptions);
+        bundleApi.createBundleTags(subscriptionJson.getBundleId(), ImmutableList.<UUID>of(bundleTagDef.getId()), requestOptions);
 
-        final Tags allBundleTags = killBillClient.getBundleTags(subscriptionJson.getBundleId(), AuditLevel.FULL, requestOptions);
+        final Tags allBundleTags = bundleApi.getBundleTags(subscriptionJson.getBundleId(), requestOptions);
         Assert.assertEquals(allBundleTags.size(), 1);
 
-        final Tags allAccountTags = killBillClient.getAllAccountTags(account.getAccountId(), null, AuditLevel.FULL, requestOptions);
+        final Tags allAccountTags = accountApi.getAllTags(account.getAccountId(), null, requestOptions);
         Assert.assertEquals(allAccountTags.size(), ControlTagType.values().length + 1);
 
-
-        final Tags allBundleTagsForAccount = killBillClient.getAllAccountTags(account.getAccountId(), ObjectType.BUNDLE.name(), AuditLevel.FULL, requestOptions);
+        final Tags allBundleTagsForAccount = accountApi.getAllTags(account.getAccountId(), ObjectType.BUNDLE, requestOptions);
         Assert.assertEquals(allBundleTagsForAccount.size(), 1);
     }
 
-
     @Test(groups = "slow", description = "Can search system tags")
     public void testSystemTagsPagination() throws Exception {
         final Account account = createAccount();
         for (final ControlTagType controlTagType : ControlTagType.values()) {
-            killBillClient.createAccountTag(account.getAccountId(), controlTagType.getId(), requestOptions);
+            accountApi.createAccountTags(account.getAccountId(), ImmutableList.<UUID>of(controlTagType.getId()), requestOptions);
         }
 
-        final Tags allTags = killBillClient.getTags(requestOptions);
+        final Tags allTags = accountApi.getAccountTags(account.getAccountId(), requestOptions);
         Assert.assertEquals(allTags.size(), ControlTagType.values().length);
 
         for (final ControlTagType controlTagType : ControlTagType.values()) {
-            Assert.assertEquals(killBillClient.searchTags(controlTagType.toString(), requestOptions).size(), 1);
-            Assert.assertEquals(killBillClient.searchTags(controlTagType.getDescription(), requestOptions).size(), 1);
+            Assert.assertEquals(tagApi.searchTags(controlTagType.toString(), requestOptions).size(), 1);
+            // TODO Hack until we fix client api
+
+            Assert.assertEquals(tagApi.searchTags(UTF8UrlEncoder.encodePath(controlTagType.getDescription()), requestOptions).size(), 1);
         }
     }
 
@@ -161,7 +161,7 @@ public class TestTag extends TestJaxrsBase {
         final Account account = createAccount();
 
         try {
-            killBillClient.createAccountTag(account.getAccountId(), SystemTags.PARK_TAG_DEFINITION_ID, requestOptions);
+            accountApi.createAccountTags(account.getAccountId(), ImmutableList.<UUID>of(SystemTags.PARK_TAG_DEFINITION_ID), requestOptions);
             Assert.fail("Creating a tag associated with a system tag should fail");
         } catch (final Exception e) {
             Assert.assertTrue(true);
@@ -172,13 +172,16 @@ public class TestTag extends TestJaxrsBase {
     public void testGetTagAuditLogsWithHistory() throws Exception {
         final Account accountJson = createAccount();
         assertNotNull(accountJson);
+        final TagDefinition accountTagDefInput = new TagDefinition()
+                .setName("tag_name")
+                .setDescription("nothing special")
+                .setApplicableObjectTypes(ImmutableList.<ObjectType>of(ObjectType.ACCOUNT));
 
-        final TagDefinition accountTagDefInput = new TagDefinition(null, false, "accounttagdef", "nothing special",  ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
-        final TagDefinition accountTagDef = killBillClient.createTagDefinition(accountTagDefInput, requestOptions);
-        killBillClient.createAccountTag(accountJson.getAccountId(), accountTagDef.getId(), requestOptions);
+        final TagDefinition accountTagDef = tagDefinitionApi.createTagDefinition(accountTagDefInput, requestOptions);
+        accountApi.createAccountTags(accountJson.getAccountId(), ImmutableList.<UUID>of(accountTagDef.getId()), requestOptions);
 
         // get all audit for the account
-        final List<AuditLog> auditLogsJson = killBillClient.getAccountAuditLogs(accountJson.getAccountId());
+        final List<AuditLog> auditLogsJson = accountApi.getAccountAuditLogs(accountJson.getAccountId(), requestOptions);
         Assert.assertEquals(auditLogsJson.size(), 2);
         UUID objectId = null;
         for (AuditLog auditLog : auditLogsJson) {
@@ -188,7 +191,7 @@ public class TestTag extends TestJaxrsBase {
             }
         }
         assertNotNull(objectId);
-        final List<AuditLog> tagAuditLogWithHistories = killBillClient.getTagAuditLogsWithHistory(accountJson.getAccountId(), objectId);
+        final List<AuditLog> tagAuditLogWithHistories = tagApi.getTagAuditLogsWithHistory(objectId, requestOptions);
         assertEquals(tagAuditLogWithHistories.size(), 1);
         assertEquals(tagAuditLogWithHistories.get(0).getChangeType(), ChangeType.INSERT.toString());
         assertEquals(tagAuditLogWithHistories.get(0).getObjectType(), ObjectType.TAG);
@@ -199,26 +202,31 @@ public class TestTag extends TestJaxrsBase {
         assertEquals(history1.get("tagDefinitionId"), accountTagDef.getId().toString());
         assertEquals(history1.get("objectId"), accountJson.getAccountId().toString());
         assertEquals(history1.get("objectType"), ObjectType.ACCOUNT.toString());
-
     }
 
     @Test(groups = "slow", description = "Can paginate through all tags")
     public void testTagsPagination() throws Exception {
         final Account account = createAccount();
         for (int i = 0; i < 5; i++) {
-            final TagDefinition tagDefinition = new TagDefinition(null, false, UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID().toString(), ImmutableList.<ObjectType>of(ObjectType.ACCOUNT));
-            final UUID tagDefinitionId = killBillClient.createTagDefinition(tagDefinition, requestOptions).getId();
-            killBillClient.createAccountTag(account.getAccountId(), tagDefinitionId, requestOptions);
+            final TagDefinition tagDefinition = new TagDefinition(null, false, UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID().toString(), ImmutableList.<ObjectType>of(ObjectType.ACCOUNT), null);
+            final UUID tagDefinitionId = tagDefinitionApi.createTagDefinition(tagDefinition, requestOptions).getId();
+            accountApi.createAccountTags(account.getAccountId(), ImmutableList.<UUID>of(tagDefinitionId), requestOptions);
         }
 
-        final Tags allTags = killBillClient.getTags(requestOptions);
+        final Tags allTags = accountApi.getAccountTags(account.getAccountId(), requestOptions);
         Assert.assertEquals(allTags.size(), 5);
 
-        Tags page = killBillClient.getTags(0L, 1L, requestOptions);
+        Tags page = tagApi.getTags(0L, 1L, AuditLevel.NONE, requestOptions);
         for (int i = 0; i < 5; i++) {
             Assert.assertNotNull(page);
             Assert.assertEquals(page.size(), 1);
-            Assert.assertEquals(page.get(0), allTags.get(i));
+            final Tag targetTag = page.get(0);
+            Assert.assertTrue(Iterables.any(allTags, new Predicate<Tag>() {
+                @Override
+                public boolean apply(@Nullable final Tag input) {
+                    return input.equals(targetTag);
+                }
+            }));
             page = page.getNext();
         }
         Assert.assertNull(page);
@@ -228,11 +236,11 @@ public class TestTag extends TestJaxrsBase {
             doSearchTag(tag.getTagId().toString(), tag);
             doSearchTag(tag.getTagDefinitionName(), tag);
 
-            final TagDefinition tagDefinition = killBillClient.getTagDefinition(tag.getTagDefinitionId(), requestOptions);
+            final TagDefinition tagDefinition = tagDefinitionApi.getTagDefinition(tag.getTagDefinitionId(), requestOptions);
             doSearchTag(tagDefinition.getDescription(), tag);
         }
 
-        final Tags tags = killBillClient.searchTags(ObjectType.ACCOUNT.toString(), requestOptions);
+        final Tags tags = tagApi.searchTags(ObjectType.ACCOUNT.toString(), requestOptions);
         Assert.assertEquals(tags.size(), 5);
         Assert.assertEquals(tags.getPaginationCurrentOffset(), 0);
         Assert.assertEquals(tags.getPaginationTotalNbRecords(), 5);
@@ -240,7 +248,7 @@ public class TestTag extends TestJaxrsBase {
     }
 
     private void doSearchTag(final String searchKey, @Nullable final Tag expectedTag) throws KillBillClientException {
-        final Tags tags = killBillClient.searchTags(searchKey, requestOptions);
+        final Tags tags = tagApi.searchTags(searchKey, requestOptions);
         if (expectedTag == null) {
             Assert.assertTrue(tags.isEmpty());
             Assert.assertEquals(tags.getPaginationCurrentOffset(), 0);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
index 80a3363..1acaec4 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
@@ -23,29 +23,28 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.awaitility.Awaitility;
+import org.awaitility.Duration;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.RequestOptions;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.ComboPaymentTransaction;
-import org.killbill.billing.client.model.Payment;
-import org.killbill.billing.client.model.PaymentMethod;
-import org.killbill.billing.client.model.PaymentMethodPluginDetail;
-import org.killbill.billing.client.model.PaymentTransaction;
-import org.killbill.billing.client.model.PluginProperty;
-import org.killbill.billing.client.model.Tenant;
-import org.killbill.billing.client.model.TenantKey;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.ComboPaymentTransaction;
+import org.killbill.billing.client.model.gen.Payment;
+import org.killbill.billing.client.model.gen.PaymentMethod;
+import org.killbill.billing.client.model.gen.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.gen.PaymentTransaction;
+import org.killbill.billing.client.model.gen.PluginProperty;
+import org.killbill.billing.client.model.gen.Tenant;
+import org.killbill.billing.client.model.gen.TenantKeyValue;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.payment.api.TransactionStatus;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.tenant.api.TenantKV;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.Resources;
-import org.awaitility.Awaitility;
-import org.awaitility.Duration;
 
 public class TestTenantKV extends TestJaxrsBase {
 
@@ -53,18 +52,18 @@ public class TestTenantKV extends TestJaxrsBase {
     public void testPerTenantPluginConfig() throws Exception {
         final String pluginName = "PLUGIN_FOO";
 
-        final String pluginPath = Resources.getResource("plugin.yml").getPath();
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        final TenantKey tenantKey0 = killBillClient.registerPluginConfigurationForTenant(pluginName, pluginPath, createdBy, reason, comment);
+        final String pluginConfig = getResourceBodyString("plugin.yml");
+        final TenantKeyValue tenantKey0 = tenantApi.uploadPluginConfiguration(pluginName, pluginConfig, requestOptions);
         callbackServlet.assertListenerStatus();
         Assert.assertEquals(tenantKey0.getKey(), TenantKV.TenantKey.PLUGIN_CONFIG_.toString() + pluginName);
 
-        final TenantKey tenantKey1 = killBillClient.getPluginConfigurationForTenant(pluginName);
+        final TenantKeyValue tenantKey1 = tenantApi.getPluginConfiguration(pluginName, requestOptions);
         Assert.assertEquals(tenantKey1.getKey(), TenantKV.TenantKey.PLUGIN_CONFIG_.toString() + pluginName);
         Assert.assertEquals(tenantKey1.getValues().size(), 1);
 
-        killBillClient.unregisterPluginConfigurationForTenant(pluginName, createdBy, reason, comment);
-        final TenantKey tenantKey2 = killBillClient.getPluginConfigurationForTenant(pluginName);
+        tenantApi.deletePluginConfiguration(pluginName, requestOptions);
+        final TenantKeyValue tenantKey2 = tenantApi.getPluginConfiguration(pluginName, requestOptions);
         Assert.assertEquals(tenantKey2.getKey(), TenantKV.TenantKey.PLUGIN_CONFIG_.toString() + pluginName);
         Assert.assertEquals(tenantKey2.getValues().size(), 0);
     }
@@ -77,21 +76,21 @@ public class TestTenantKV extends TestJaxrsBase {
         final Tenant otherTenantWithDifferentStateMachine = createTenant(UUID.randomUUID().toString(), UUID.randomUUID().toString(), true);
 
         // Verify initial state
-        final TenantKey emptyTenantKey = killBillClient.getPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptionsForOriginalTenant);
+        final TenantKeyValue emptyTenantKey = tenantApi.getPluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptionsForOriginalTenant);
         Assert.assertEquals(emptyTenantKey.getValues().size(), 0);
-        final TenantKey emptyTenantKeyOtherTenant = killBillClient.getPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptions);
+        final TenantKeyValue emptyTenantKeyOtherTenant = tenantApi.getPluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptions);
         Assert.assertEquals(emptyTenantKeyOtherTenant.getValues().size(), 0);
 
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_CHANGE);
-        final String stateMachineConfigPath = Resources.getResource("SimplePaymentStates.xml").getPath();
-        final TenantKey tenantKey0 = killBillClient.registerPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, stateMachineConfigPath, requestOptions);
+        final String stateMachineConfig = getResourceBodyString("SimplePaymentStates.xml");
+        final TenantKeyValue tenantKey0 = tenantApi.uploadPluginPaymentStateMachineConfig(PLUGIN_NAME, stateMachineConfig, requestOptions);
         callbackServlet.assertListenerStatus();
         Assert.assertEquals(tenantKey0.getKey(), TenantKV.TenantKey.PLUGIN_PAYMENT_STATE_MACHINE_.toString() + PLUGIN_NAME);
 
         // Verify only the other tenant has the new state machine
-        final TenantKey emptyTenantKey1 = killBillClient.getPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptionsForOriginalTenant);
+        final TenantKeyValue emptyTenantKey1 = tenantApi.getPluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptionsForOriginalTenant);
         Assert.assertEquals(emptyTenantKey1.getValues().size(), 0);
-        final TenantKey tenantKey1OtherTenant = killBillClient.getPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptions);
+        final TenantKeyValue tenantKey1OtherTenant = tenantApi.getPluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptions);
         Assert.assertEquals(tenantKey1OtherTenant.getKey(), TenantKV.TenantKey.PLUGIN_PAYMENT_STATE_MACHINE_.toString() + PLUGIN_NAME);
         Assert.assertEquals(tenantKey1OtherTenant.getValues().size(), 1);
 
@@ -101,14 +100,15 @@ public class TestTenantKV extends TestJaxrsBase {
 
         // Void in the first tenant (allowed by the default state machine)
         callbackServlet.pushExpectedEvent(ExtBusEventType.PAYMENT_SUCCESS);
-        final Payment voidPayment = killBillClient.voidPayment(payment.getPaymentId(), payment.getPaymentExternalKey(), UUID.randomUUID().toString(), ImmutableList.<String>of(), ImmutableMap.<String, String>of(), requestOptionsForOriginalTenant);
+        paymentApi.voidPayment(payment.getPaymentId(), new PaymentTransaction(), NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptionsForOriginalTenant);
         callbackServlet.assertListenerStatus();
-        Assert.assertEquals(voidPayment.getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS.toString());
-        Assert.assertEquals(voidPayment.getTransactions().get(1).getStatus(), TransactionStatus.SUCCESS.toString());
+        final Payment voidPayment = paymentApi.getPayment(payment.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptionsForOriginalTenant);
+        Assert.assertEquals(voidPayment.getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS);
+        Assert.assertEquals(voidPayment.getTransactions().get(1).getStatus(), TransactionStatus.SUCCESS);
 
         // Void in the other tenant (disallowed)
         try {
-            killBillClient.voidPayment(paymentOtherTenant.getPaymentId(), paymentOtherTenant.getPaymentExternalKey(), UUID.randomUUID().toString(), ImmutableList.<String>of(), ImmutableMap.<String, String>of(), requestOptions);
+            paymentApi.voidPayment(paymentOtherTenant.getPaymentId(), new PaymentTransaction(), NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals((int) e.getBillingException().getCode(), ErrorCode.PAYMENT_INVALID_OPERATION.getCode());
@@ -117,9 +117,9 @@ public class TestTenantKV extends TestJaxrsBase {
 
         // Remove the custom state machine
         callbackServlet.pushExpectedEvent(ExtBusEventType.TENANT_CONFIG_DELETION);
-        killBillClient.unregisterPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptions);
+        tenantApi.deletePluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptions);
+        final TenantKeyValue tenantKey2 = tenantApi.getPluginPaymentStateMachineConfig(PLUGIN_NAME, requestOptions);
         callbackServlet.assertListenerStatus();
-        final TenantKey tenantKey2 = killBillClient.getPluginPaymentStateMachineConfigurationForTenant(PLUGIN_NAME, requestOptions);
         Assert.assertEquals(tenantKey2.getKey(), TenantKV.TenantKey.PLUGIN_PAYMENT_STATE_MACHINE_.toString() + PLUGIN_NAME);
         Assert.assertEquals(tenantKey2.getValues().size(), 0);
 
@@ -133,7 +133,8 @@ public class TestTenantKV extends TestJaxrsBase {
                           // The void should now go through
                           try {
                               callbackServlet.pushExpectedEvent(ExtBusEventType.PAYMENT_SUCCESS);
-                              final Payment voidPaymentOtherTenant2 = killBillClient.voidPayment(paymentOtherTenant.getPaymentId(), paymentOtherTenant.getPaymentExternalKey(), UUID.randomUUID().toString(), ImmutableList.<String>of(), ImmutableMap.<String, String>of(), requestOptions);
+                              paymentApi.voidPayment(paymentOtherTenant.getPaymentId(), new PaymentTransaction(), NULL_PLUGIN_NAMES, NULL_PLUGIN_PROPERTIES, requestOptions);
+                              final Payment voidPaymentOtherTenant2 = paymentApi.getPayment(paymentOtherTenant.getPaymentId(), NULL_PLUGIN_PROPERTIES, requestOptions);
                               callbackServlet.assertListenerStatus();
                               voidPaymentOtherTenant2Ref.set(voidPaymentOtherTenant2);
                               return voidPaymentOtherTenant2 != null;
@@ -143,8 +144,8 @@ public class TestTenantKV extends TestJaxrsBase {
                           }
                       }
                   });
-        Assert.assertEquals(voidPaymentOtherTenant2Ref.get().getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS.toString());
-        Assert.assertEquals(voidPaymentOtherTenant2Ref.get().getTransactions().get(1).getStatus(), TransactionStatus.SUCCESS.toString());
+        Assert.assertEquals(voidPaymentOtherTenant2Ref.get().getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS);
+        Assert.assertEquals(voidPaymentOtherTenant2Ref.get().getTransactions().get(1).getStatus(), TransactionStatus.SUCCESS);
     }
 
     private Payment createComboPaymentTransaction(final RequestOptions requestOptions) throws KillBillClientException {
@@ -155,7 +156,7 @@ public class TestTenantKV extends TestJaxrsBase {
         info.setProperties(null);
 
         final String paymentMethodExternalKey = UUID.randomUUID().toString();
-        final PaymentMethod paymentMethodJson = new PaymentMethod(null, paymentMethodExternalKey, null, true, PLUGIN_NAME, info);
+        final PaymentMethod paymentMethodJson = new PaymentMethod(null, paymentMethodExternalKey, null, true, PLUGIN_NAME, info, null);
 
         final String authTransactionExternalKey = UUID.randomUUID().toString();
         final PaymentTransaction authTransactionJson = new PaymentTransaction();
@@ -163,13 +164,13 @@ public class TestTenantKV extends TestJaxrsBase {
         authTransactionJson.setCurrency(accountJson.getCurrency());
         authTransactionJson.setPaymentExternalKey(UUID.randomUUID().toString());
         authTransactionJson.setTransactionExternalKey(authTransactionExternalKey);
-        authTransactionJson.setTransactionType("AUTHORIZE");
+        authTransactionJson.setTransactionType(TransactionType.AUTHORIZE);
 
         callbackServlet.pushExpectedEvents(ExtBusEventType.ACCOUNT_CREATION, ExtBusEventType.ACCOUNT_CHANGE, ExtBusEventType.PAYMENT_SUCCESS);
-        final ComboPaymentTransaction comboAuthorization = new ComboPaymentTransaction(accountJson, paymentMethodJson, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of());
-        final Payment payment = killBillClient.createPayment(comboAuthorization, ImmutableMap.<String, String>of(), requestOptions);
+        final ComboPaymentTransaction comboAuthorization = new ComboPaymentTransaction(accountJson, paymentMethodJson, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of(), null);
+        final Payment payment = paymentApi.createComboPayment(comboAuthorization, NULL_PLUGIN_NAMES, requestOptions);
         callbackServlet.assertListenerStatus();
-        Assert.assertEquals(payment.getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS.toString());
+        Assert.assertEquals(payment.getTransactions().get(0).getStatus(), TransactionStatus.SUCCESS);
 
         return payment;
     }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java
index e20f909..689aa8e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java
@@ -24,15 +24,16 @@ import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Bundle;
-import org.killbill.billing.client.model.InvoiceItem;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.RolledUpUsage;
-import org.killbill.billing.client.model.Subscription;
-import org.killbill.billing.client.model.SubscriptionUsageRecord;
-import org.killbill.billing.client.model.UnitUsageRecord;
-import org.killbill.billing.client.model.UsageRecord;
+import org.killbill.billing.client.model.Subscriptions;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Bundle;
+import org.killbill.billing.client.model.gen.InvoiceItem;
+import org.killbill.billing.client.model.gen.RolledUpUsage;
+import org.killbill.billing.client.model.gen.Subscription;
+import org.killbill.billing.client.model.gen.SubscriptionUsageRecord;
+import org.killbill.billing.client.model.gen.UnitUsageRecord;
+import org.killbill.billing.client.model.gen.UsageRecord;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.util.api.AuditLevel;
@@ -71,10 +72,15 @@ public class TestUsage extends TestJaxrsBase {
                                            ExtBusEventType.SUBSCRIPTION_CREATION,
                                            ExtBusEventType.SUBSCRIPTION_CREATION,
                                            ExtBusEventType.INVOICE_CREATION);
-        final Bundle bundle = killBillClient.createSubscriptionWithAddOns(ImmutableList.<Subscription>of(base, addOn),
-                                                                          null,
-                                                                          DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC,
-                                                                          requestOptions);
+        final Subscriptions body = new Subscriptions();
+        body.add(base);
+        body.add(addOn);
+
+        final Bundle bundle = subscriptionApi.createSubscriptionWithAddOns(body,
+                                                                           null,
+                                                                           null,
+                                                                           NULL_PLUGIN_PROPERTIES,
+                                                                           requestOptions);
         callbackServlet.assertListenerStatus();
         final UUID addOnSubscriptionId = Iterables.<Subscription>find(bundle.getSubscriptions(),
                                                                       new Predicate<Subscription>() {
@@ -102,29 +108,29 @@ public class TestUsage extends TestJaxrsBase {
         usage.setSubscriptionId(addOnSubscriptionId);
         usage.setUnitUsageRecords(ImmutableList.<UnitUsageRecord>of(unitUsageRecord));
 
-        killBillClient.createSubscriptionUsageRecord(usage, requestOptions);
+        usageApi.recordUsage(usage, requestOptions);
         callbackServlet.assertListenerStatus();
 
-        final RolledUpUsage retrievedUsage1 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday(), requestOptions);
+        final RolledUpUsage retrievedUsage1 = usageApi.getUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday(), requestOptions);
         Assert.assertEquals(retrievedUsage1.getSubscriptionId(), usage.getSubscriptionId());
         Assert.assertEquals(retrievedUsage1.getRolledUpUnits().size(), 1);
         Assert.assertEquals(retrievedUsage1.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
         // endDate is excluded
         Assert.assertEquals((long) retrievedUsage1.getRolledUpUnits().get(0).getAmount(), 10);
 
-        final RolledUpUsage retrievedUsage2 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday().plusDays(1), requestOptions);
+        final RolledUpUsage retrievedUsage2 = usageApi.getUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday().plusDays(1), requestOptions);
         Assert.assertEquals(retrievedUsage2.getSubscriptionId(), usage.getSubscriptionId());
         Assert.assertEquals(retrievedUsage2.getRolledUpUnits().size(), 1);
         Assert.assertEquals(retrievedUsage2.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
         Assert.assertEquals((long) retrievedUsage2.getRolledUpUnits().get(0).getAmount(), 15);
 
-        final RolledUpUsage retrievedUsage3 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday(), clock.getUTCToday().plusDays(1), requestOptions);
+        final RolledUpUsage retrievedUsage3 = usageApi.getUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday(), clock.getUTCToday().plusDays(1), requestOptions);
         Assert.assertEquals(retrievedUsage3.getSubscriptionId(), usage.getSubscriptionId());
         Assert.assertEquals(retrievedUsage3.getRolledUpUnits().size(), 1);
         Assert.assertEquals(retrievedUsage3.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
         Assert.assertEquals((long) retrievedUsage3.getRolledUpUnits().get(0).getAmount(), 5);
 
-        final RolledUpUsage retrievedUsage4 = killBillClient.getRolledUpUsage(addOnSubscriptionId, null, clock.getUTCToday(), clock.getUTCToday().plusDays(1), requestOptions);
+        final RolledUpUsage retrievedUsage4 = usageApi.getAllUsage(addOnSubscriptionId, clock.getUTCToday(), clock.getUTCToday().plusDays(1), requestOptions);
         Assert.assertEquals(retrievedUsage4.getSubscriptionId(), usage.getSubscriptionId());
         Assert.assertEquals(retrievedUsage4.getRolledUpUnits().size(), 1);
         Assert.assertEquals(retrievedUsage4.getRolledUpUnits().get(0).getUnitType(), "bullets");
@@ -137,13 +143,13 @@ public class TestUsage extends TestJaxrsBase {
         clock.addMonths(1);
         callbackServlet.assertListenerStatus();
 
-        final Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.MINIMAL, requestOptions);
+        final Invoices invoices = accountApi.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, false, AuditLevel.MINIMAL, requestOptions);
         Assert.assertEquals(invoices.size(), 2);
 
-        final InvoiceItem usageItem =  Iterables.tryFind(invoices.get(1).getItems(), new Predicate<InvoiceItem>() {
+        final InvoiceItem usageItem = Iterables.tryFind(invoices.get(1).getItems(), new Predicate<InvoiceItem>() {
             @Override
             public boolean apply(final InvoiceItem input) {
-                return InvoiceItemType.valueOf(input.getItemType()) == InvoiceItemType.USAGE;
+                return input.getItemType() == InvoiceItemType.USAGE;
             }
         }).orNull();
         Assert.assertNotNull(usageItem);
@@ -172,9 +178,14 @@ public class TestUsage extends TestJaxrsBase {
         addOn.setBillingPeriod(BillingPeriod.NO_BILLING_PERIOD);
         addOn.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        final Bundle bundle = killBillClient.createSubscriptionWithAddOns(ImmutableList.<Subscription>of(base, addOn),
-                                                                          null,
-                                                                          DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, requestOptions);
+        final Subscriptions body = new Subscriptions();
+        body.add(base);
+        body.add(addOn);
+
+        final Bundle bundle = subscriptionApi.createSubscriptionWithAddOns(body,
+                                                                           null,
+                                                                           null,
+                                                                           NULL_PLUGIN_PROPERTIES, requestOptions);
         final UUID addOnSubscriptionId = Iterables.<Subscription>find(bundle.getSubscriptions(),
                                                                       new Predicate<Subscription>() {
                                                                           @Override
@@ -196,13 +207,12 @@ public class TestUsage extends TestJaxrsBase {
         usage.setTrackingId(UUID.randomUUID().toString());
         usage.setUnitUsageRecords(ImmutableList.<UnitUsageRecord>of(unitUsageRecord));
 
-        killBillClient.createSubscriptionUsageRecord(usage, requestOptions);
+        usageApi.recordUsage(usage, requestOptions);
 
         try {
-            killBillClient.createSubscriptionUsageRecord(usage, requestOptions );
+            usageApi.recordUsage(usage, requestOptions);
             Assert.fail();
-        }
-        catch (final KillBillClientException e) {
+        } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getBillingException().getCode(), (Integer) ErrorCode.USAGE_RECORD_TRACKING_ID_ALREADY_EXISTS.getCode());
         }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestTenantFilter.java b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestTenantFilter.java
index 4e64cf8..88bb985 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestTenantFilter.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestTenantFilter.java
@@ -21,8 +21,8 @@ package org.killbill.billing.server.security;
 import javax.ws.rs.core.Response.Status;
 
 import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Tenant;
+import org.killbill.billing.client.model.gen.Account;
+import org.killbill.billing.client.model.gen.Tenant;
 import org.killbill.billing.jaxrs.TestJaxrsBase;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
@@ -45,7 +45,7 @@ public class TestTenantFilter extends TestJaxrsBase {
         // Try to create an account without being logged-in
         logoutTenant();
         try {
-            killBillClient.createAccount(getAccount(), createdBy, reason, comment);
+            accountApi.createAccount(getAccount(), requestOptions);
             Assert.fail();
         } catch (final KillBillClientException e) {
             Assert.assertEquals(e.getResponse().getStatusCode(), Status.UNAUTHORIZED.getStatusCode());
@@ -56,7 +56,7 @@ public class TestTenantFilter extends TestJaxrsBase {
         final Tenant tenant1 = createTenant("pierre", "pierreIsFr3nch", true);
 
         final Account account1 = createAccount();
-        Assert.assertEquals(killBillClient.getAccount(account1.getExternalKey()), account1);
+        Assert.assertEquals(accountApi.getAccountByKey(account1.getExternalKey(), requestOptions), account1);
 
         logoutTenant();
 
@@ -64,13 +64,13 @@ public class TestTenantFilter extends TestJaxrsBase {
         createTenant("stephane", "stephane1sAlsoFr3nch", true);
 
         final Account account2 = createAccount();
-        Assert.assertEquals(killBillClient.getAccount(account2.getExternalKey()), account2);
+        Assert.assertEquals(accountApi.getAccountByKey(account2.getExternalKey(), requestOptions), account2);
 
         // We should not be able to retrieve the first account as tenant2
-        Assert.assertNull(killBillClient.getAccount(account1.getExternalKey()));
+        Assert.assertNull(accountApi.getAccountByKey(account1.getExternalKey(), requestOptions));
 
         // Same for tenant1 and account2
         loginTenant(tenant1.getApiKey(), tenant1.getApiSecret());
-        Assert.assertNull(killBillClient.getAccount(account2.getExternalKey()));
+        Assert.assertNull(accountApi.getAccountByKey(account2.getExternalKey(), requestOptions));
     }
 }
diff --git a/profiles/killpay/pom.xml b/profiles/killpay/pom.xml
index 5c3e213..fbb4bca 100644
--- a/profiles/killpay/pom.xml
+++ b/profiles/killpay/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killpay</artifactId>

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

diff --git a/profiles/pom.xml b/profiles/pom.xml
index 4e63936..7be834c 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles</artifactId>
diff --git a/subscription/pom.xml b/subscription/pom.xml
index 6bab51f..9c2bd48 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
index 278ea3c..35bd5e1 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
@@ -208,7 +208,7 @@ public class PlanAligner extends BaseAligner {
         final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getName());
 
         final DateTime planStartDate;
-        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, catalogEffectiveDate);
+        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, catalogEffectiveDate, subscriptionStartDate);
         switch (alignment) {
             case START_OF_SUBSCRIPTION:
                 planStartDate = subscriptionStartDate;
@@ -271,7 +271,7 @@ public class PlanAligner extends BaseAligner {
         final PlanSpecifier toPlanSpecifier = new PlanSpecifier(nextPlan.getName());
         final PhaseType initialPhase;
         final DateTime planStartDate;
-        final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, catalogEffectiveDate);
+        final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, catalogEffectiveDate, subscriptionStartDate);
         switch (alignment) {
             case START_OF_SUBSCRIPTION:
                 planStartDate = subscriptionStartDate;
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
index 82cc967..79774ef 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
@@ -17,20 +17,47 @@
 package org.killbill.billing.subscription.api;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.UUID;
 
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.CatalogInternalApi;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanChangeResult;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
+import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.subscription.api.svcs.DefaultPlanPhasePriceOverridesWithCallContext;
+import org.killbill.billing.subscription.api.svcs.DefaultSubscriptionInternalApi;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
+import org.killbill.billing.subscription.engine.addon.AddonUtils;
 import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
+import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
+import org.killbill.billing.util.UUIDs;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.clock.Clock;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 
 public class SubscriptionApiBase {
 
@@ -44,11 +71,215 @@ public class SubscriptionApiBase {
         this.apiService = apiService;
         this.clock = clock;
     }
-    protected List<SubscriptionBase> createSubscriptionsForApiUse(final List<SubscriptionBase> internalSubscriptions) {
-        return new ArrayList<SubscriptionBase>(Collections2.transform(internalSubscriptions, new Function<SubscriptionBase, SubscriptionBase>() {
+
+    protected SubscriptionBaseBundle getActiveBundleForKey(final String bundleKey, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+        final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(bundleKey, context);
+        for (final SubscriptionBaseBundle cur : existingBundles) {
+            final List<DefaultSubscriptionBase> subscriptions = dao.getSubscriptions(cur.getId(), ImmutableList.<SubscriptionBaseEvent>of(), catalog, context);
+            for (final SubscriptionBase s : subscriptions) {
+                if (s.getCategory() == ProductCategory.ADD_ON) {
+                    continue;
+                }
+                if (s.getEndDate() == null || s.getEndDate().compareTo(clock.getUTCNow()) > 0) {
+                    return cur;
+                }
+            }
+        }
+        return null;
+    }
+
+    protected SubscriptionBase getBaseSubscription(final UUID bundleId,
+                                                   final Catalog catalog,
+                                                   final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        final SubscriptionBase result = dao.getBaseSubscription(bundleId, catalog, context);
+        if (result == null) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
+        }
+        return createSubscriptionForApiUse(result);
+    }
+
+    protected List<DefaultSubscriptionBase> getSubscriptionsForBundle(final UUID bundleId,
+                                                                      @Nullable final DryRunArguments dryRunArguments,
+                                                                      final Catalog catalog,
+                                                                      final AddonUtils addonUtils,
+                                                                      final TenantContext tenantContext,
+                                                                      final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
+
+        final List<SubscriptionBaseEvent> outputDryRunEvents = new ArrayList<SubscriptionBaseEvent>();
+        final List<DefaultSubscriptionBase> outputSubscriptions = new ArrayList<DefaultSubscriptionBase>();
+
+        populateDryRunEvents(bundleId, dryRunArguments, outputDryRunEvents, outputSubscriptions, catalog, addonUtils, tenantContext, context);
+        final List<DefaultSubscriptionBase> result = dao.getSubscriptions(bundleId, outputDryRunEvents, catalog, context);
+        if (result != null && !result.isEmpty()) {
+            outputSubscriptions.addAll(result);
+        }
+        Collections.sort(outputSubscriptions, DefaultSubscriptionInternalApi.SUBSCRIPTIONS_COMPARATOR);
+
+        return createSubscriptionsForApiUse(outputSubscriptions);
+    }
+
+    private void populateDryRunEvents(@Nullable final UUID bundleId,
+                                      @Nullable final DryRunArguments dryRunArguments,
+                                      final Collection<SubscriptionBaseEvent> outputDryRunEvents,
+                                      final Collection<DefaultSubscriptionBase> outputSubscriptions,
+                                      final Catalog catalog,
+                                      final AddonUtils addonUtils,
+                                      final TenantContext tenantContext,
+                                      final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        if (dryRunArguments == null || dryRunArguments.getAction() == null) {
+            return;
+        }
+
+        final DateTime utcNow = clock.getUTCNow();
+        List<SubscriptionBaseEvent> dryRunEvents = null;
+        final PlanPhaseSpecifier inputSpec = dryRunArguments.getPlanPhaseSpecifier();
+        final boolean isInputSpecNullOrEmpty = inputSpec == null ||
+                                               (inputSpec.getPlanName() == null && inputSpec.getProductName() == null && inputSpec.getBillingPeriod() == null);
+
+        // Create an overridesWithContext with a null context to indicate this is dryRun and no price overridden plan should be created.
+        final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(dryRunArguments.getPlanPhasePriceOverrides(), null);
+        final Plan plan = isInputSpecNullOrEmpty ?
+                          null :
+                          catalog.createOrFindPlan(inputSpec, overridesWithContext, utcNow);
+
+        switch (dryRunArguments.getAction()) {
+            case START_BILLING:
+                final SubscriptionBase baseSubscription = dao.getBaseSubscription(bundleId, catalog, context);
+                final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
+                final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, addonUtils, context);
+                final UUID subscriptionId = UUIDs.randomUUID();
+                dryRunEvents = apiService.getEventsOnCreation(subscriptionId, startEffectiveDate, bundleStartDate, plan, inputSpec.getPhaseType(), plan.getPriceListName(),
+                                                              startEffectiveDate, catalog, context);
+                final SubscriptionBuilder builder = new SubscriptionBuilder()
+                        .setId(subscriptionId)
+                        .setBundleId(bundleId)
+                        .setBundleExternalKey(null)
+                        .setCategory(plan.getProduct().getCategory())
+                        .setBundleStartDate(bundleStartDate)
+                        .setAlignStartDate(startEffectiveDate);
+                final DefaultSubscriptionBase newSubscription = new DefaultSubscriptionBase(builder, apiService, clock);
+                newSubscription.rebuildTransitions(dryRunEvents, catalog);
+                outputSubscriptions.add(newSubscription);
+                break;
+
+            case CHANGE:
+                final DefaultSubscriptionBase subscriptionForChange = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), catalog, context);
+
+                DateTime changeEffectiveDate = getDryRunEffectiveDate(dryRunArguments.getEffectiveDate(), subscriptionForChange, context);
+                if (changeEffectiveDate == null) {
+                    BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
+                    if (policy == null) {
+                        final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange, inputSpec, utcNow, tenantContext);
+                        policy = planChangeResult.getPolicy();
+                    }
+                    // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
+                    changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy, null, -1, context);
+                }
+                dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, plan.getPriceListName(), changeEffectiveDate, true, catalog, context);
+                break;
+
+            case STOP_BILLING:
+                final DefaultSubscriptionBase subscriptionForCancellation = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), catalog, context);
+
+                DateTime cancelEffectiveDate = getDryRunEffectiveDate(dryRunArguments.getEffectiveDate(), subscriptionForCancellation, context);
+                if (dryRunArguments.getEffectiveDate() == null) {
+                    BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
+                    if (policy == null) {
+                        final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
+                        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getName(),
+                                                                               subscriptionForCancellation.getCurrentPhase().getPhaseType());
+                        policy = catalog.planCancelPolicy(spec, clock.getUTCNow(), subscriptionForCancellation.getStartDate());
+                    }
+                    // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
+                    cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy, null, -1, context);
+                }
+                dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, true, catalog, context);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unexpected dryRunArguments action " + dryRunArguments.getAction());
+        }
+
+        if (dryRunEvents != null && !dryRunEvents.isEmpty()) {
+            outputDryRunEvents.addAll(dryRunEvents);
+        }
+    }
+
+    private DateTime getDryRunEffectiveDate(@Nullable final LocalDate inputDate, final SubscriptionBase subscription, final InternalTenantContext context) {
+        if (inputDate == null) {
+            return null;
+        }
+
+        // We first use context account reference time to get a candidate)
+        final DateTime tmp = context.toUTCDateTime(inputDate);
+        // If we realize that the candidate is on the same LocalDate boundary as the subscription startDate but a bit prior we correct it to avoid weird things down the line
+        if (inputDate.compareTo(context.toLocalDate(subscription.getStartDate())) == 0 && tmp.compareTo(subscription.getStartDate()) < 0) {
+            return subscription.getStartDate();
+        } else {
+            return tmp;
+        }
+    }
+
+    protected DateTime getBundleStartDateWithSanity(final UUID bundleId,
+                                                    @Nullable final SubscriptionBase baseSubscription,
+                                                    final Plan plan,
+                                                    final DateTime effectiveDate,
+                                                    final AddonUtils addonUtils,
+                                                    final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        switch (plan.getProduct().getCategory()) {
+            case BASE:
+                if (baseSubscription != null &&
+                    (baseSubscription.getState() == EntitlementState.ACTIVE || baseSubscription.getState() == EntitlementState.PENDING)) {
+                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
+                }
+                return effectiveDate;
+
+            case ADD_ON:
+                if (baseSubscription == null) {
+                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BP, bundleId);
+                }
+                if (effectiveDate.isBefore(baseSubscription.getStartDate())) {
+                    throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, effectiveDate.toString(), baseSubscription.getStartDate().toString());
+                }
+                addonUtils.checkAddonCreationRights(baseSubscription, plan, effectiveDate, context);
+                return baseSubscription.getStartDate();
+
+            case STANDALONE:
+                if (baseSubscription != null) {
+                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
+                }
+                // Not really but we don't care, there is no alignment for STANDALONE subscriptions
+                return effectiveDate;
+
+            default:
+                throw new SubscriptionBaseError(String.format("Can't create subscription of type %s",
+                                                              plan.getProduct().getCategory().toString()));
+        }
+    }
+
+    protected SubscriptionBaseBundle createBundleForAccount(final UUID accountId,
+                                                            final String bundleKey,
+                                                            final boolean renameCancelledBundleIfExist,
+                                                            final Catalog catalog,
+                                                            final CacheController<UUID, UUID> accountIdCacheController,
+                                                            final InternalCallContext context) throws SubscriptionBaseApiException {
+        final DateTime now = context.getCreatedDate();
+        final DefaultSubscriptionBaseBundle bundle = new DefaultSubscriptionBaseBundle(bundleKey, accountId, now, now, now, now);
+        if (null != bundleKey && bundleKey.length() > 255) {
+            throw new SubscriptionBaseApiException(ErrorCode.EXTERNAL_KEY_LIMIT_EXCEEDED);
+        }
+
+        final SubscriptionBaseBundle subscriptionBundle = dao.createSubscriptionBundle(bundle, catalog, renameCancelledBundleIfExist, context);
+        accountIdCacheController.putIfAbsent(bundle.getId(), accountId);
+
+        return subscriptionBundle;
+    }
+
+    protected List<DefaultSubscriptionBase> createSubscriptionsForApiUse(final Collection<DefaultSubscriptionBase> internalSubscriptions) {
+        return new ArrayList<DefaultSubscriptionBase>(Collections2.transform(internalSubscriptions, new Function<SubscriptionBase, DefaultSubscriptionBase>() {
             @Override
-            public SubscriptionBase apply(final SubscriptionBase subscription) {
-                return createSubscriptionForApiUse((DefaultSubscriptionBase) subscription);
+            public DefaultSubscriptionBase apply(final SubscriptionBase subscription) {
+                return createSubscriptionForApiUse(subscription);
             }
         }));
     }
@@ -57,9 +288,12 @@ public class SubscriptionApiBase {
         return new DefaultSubscriptionBase((DefaultSubscriptionBase) internalSubscription, apiService, clock);
     }
 
-    protected DefaultSubscriptionBase createSubscriptionForApiUse(SubscriptionBuilder builder, List<SubscriptionBaseEvent> events, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+    protected DefaultSubscriptionBase createSubscriptionForApiUse(final SubscriptionBuilder builder,
+                                                                  final List<SubscriptionBaseEvent> events,
+                                                                  final Catalog catalog,
+                                                                  final InternalTenantContext context) throws CatalogApiException {
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder, apiService, clock);
-        if (events.size() > 0) {
+        if (!events.isEmpty()) {
             subscription.rebuildTransitions(events, catalog);
         }
         return subscription;
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionBaseCreateApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionBaseCreateApi.java
new file mode 100644
index 0000000..61c5429
--- /dev/null
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionBaseCreateApi.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.subscription.api.svcs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.Catalog;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.EntitlementSpecifier;
+import org.killbill.billing.subscription.api.SubscriptionApiBase;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseApiService;
+import org.killbill.billing.subscription.api.SubscriptionBaseWithAddOns;
+import org.killbill.billing.subscription.api.SubscriptionBaseWithAddOnsSpecifier;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
+import org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
+import org.killbill.billing.subscription.api.user.SubscriptionSpecifier;
+import org.killbill.billing.subscription.engine.addon.AddonUtils;
+import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
+import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
+import org.killbill.billing.util.UUIDs;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultSubscriptionBaseCreateApi extends SubscriptionApiBase {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionBaseCreateApi.class);
+
+    DefaultSubscriptionBaseCreateApi(final SubscriptionDao dao, final SubscriptionBaseApiService apiService, final Clock clock) {
+        super(dao, apiService, clock);
+    }
+
+    List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final Iterable<SubscriptionBaseWithAddOnsSpecifier> baseAndAddOnEntitlementsSpecifiers,
+                                                                       final boolean renameCancelledBundleIfExist,
+                                                                       final Catalog catalog,
+                                                                       final AddonUtils addonUtils,
+                                                                       final CacheController<UUID, UUID> accountIdCacheController,
+                                                                       final CacheController<UUID, UUID> bundleIdCacheController,
+                                                                       final CallContext callContext,
+                                                                       final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        // Prepare the subscription specifiers from the entitlement specifiers
+        final Collection<SubscriptionAndAddOnsSpecifier> baseAndAddOnSubscriptionsSpecifiers = new ArrayList<SubscriptionAndAddOnsSpecifier>();
+        for (final SubscriptionBaseWithAddOnsSpecifier baseAndAddOnEntitlementsSpecifier : baseAndAddOnEntitlementsSpecifiers) {
+            prepareSubscriptionAndAddOnsSpecifier(baseAndAddOnSubscriptionsSpecifiers,
+                                                  baseAndAddOnEntitlementsSpecifier,
+                                                  renameCancelledBundleIfExist,
+                                                  catalog,
+                                                  addonUtils,
+                                                  accountIdCacheController,
+                                                  callContext,
+                                                  context);
+        }
+
+        // Create the subscriptions
+        final List<SubscriptionBaseWithAddOns> subscriptionBaseWithAddOns = apiService.createPlansWithAddOns(callContext.getAccountId(),
+                                                                                                             baseAndAddOnSubscriptionsSpecifiers,
+                                                                                                             catalog,
+                                                                                                             callContext);
+
+        // Populate the caches
+        for (final SubscriptionBaseWithAddOns subscriptionBaseWithAO : subscriptionBaseWithAddOns) {
+            for (final SubscriptionBase subscriptionBase : subscriptionBaseWithAO.getSubscriptionBaseList()) {
+                bundleIdCacheController.putIfAbsent(subscriptionBase.getId(), subscriptionBaseWithAO.getBundle().getId());
+            }
+        }
+
+        return subscriptionBaseWithAddOns;
+    }
+
+    private void prepareSubscriptionAndAddOnsSpecifier(final Collection<SubscriptionAndAddOnsSpecifier> subscriptionAndAddOns,
+                                                       final SubscriptionBaseWithAddOnsSpecifier subscriptionBaseWithAddOnsSpecifier,
+                                                       final boolean renameCancelledBundleIfExist,
+                                                       final Catalog catalog,
+                                                       final AddonUtils addonUtils,
+                                                       final CacheController<UUID, UUID> accountIdCacheController,
+                                                       final CallContext callContext,
+                                                       final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        SubscriptionBaseBundle bundle = getBundleWithSanity(subscriptionBaseWithAddOnsSpecifier, catalog, callContext, context);
+
+        final DateTime billingRequestedDateRaw = (subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate() != null) ?
+                                                 context.toUTCDateTime(subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate()) : context.getCreatedDate();
+
+        final SubscriptionBase baseSubscription;
+        final DateTime billingRequestedDate;
+        if (bundle != null) {
+            baseSubscription = dao.getBaseSubscription(bundle.getId(), catalog, context);
+            billingRequestedDate = computeActualBillingRequestedDate(bundle, billingRequestedDateRaw, baseSubscription, catalog, context);
+        } else {
+            baseSubscription = null;
+            billingRequestedDate = billingRequestedDateRaw;
+        }
+
+        final List<EntitlementSpecifier> reorderedSpecifiers = new ArrayList<EntitlementSpecifier>();
+        final List<Plan> createdOrRetrievedPlans = new ArrayList<Plan>();
+        final boolean hasBaseOrStandalonePlanSpecifier = createPlansIfNeededAndReorderBPOrStandaloneSpecFirstWithSanity(subscriptionBaseWithAddOnsSpecifier,
+                                                                                                                        catalog,
+                                                                                                                        billingRequestedDate,
+                                                                                                                        reorderedSpecifiers,
+                                                                                                                        createdOrRetrievedPlans,
+                                                                                                                        callContext);
+
+        if (hasBaseOrStandalonePlanSpecifier && baseSubscription != null) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundle.getExternalKey());
+        }
+
+        if (bundle == null && hasBaseOrStandalonePlanSpecifier) {
+            bundle = createBundleForAccount(callContext.getAccountId(),
+                                            subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey(),
+                                            renameCancelledBundleIfExist,
+                                            catalog,
+                                            accountIdCacheController,
+                                            context);
+        } else if (bundle == null) {
+            log.warn("Invalid specifier: {}", subscriptionBaseWithAddOnsSpecifier);
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BP, subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey());
+        }
+
+        final List<SubscriptionSpecifier> subscriptionSpecifiers = verifyAndBuildSubscriptionSpecifiers(bundle,
+                                                                                                        hasBaseOrStandalonePlanSpecifier,
+                                                                                                        reorderedSpecifiers,
+                                                                                                        createdOrRetrievedPlans,
+                                                                                                        subscriptionBaseWithAddOnsSpecifier.isMigrated(),
+                                                                                                        billingRequestedDate,
+                                                                                                        catalog,
+                                                                                                        addonUtils,
+                                                                                                        callContext,
+                                                                                                        context);
+        final SubscriptionAndAddOnsSpecifier subscriptionAndAddOnsSpecifier = new SubscriptionAndAddOnsSpecifier(bundle,
+                                                                                                                 billingRequestedDate,
+                                                                                                                 subscriptionSpecifiers);
+        subscriptionAndAddOns.add(subscriptionAndAddOnsSpecifier);
+    }
+
+    private DateTime computeActualBillingRequestedDate(final SubscriptionBaseBundle bundle,
+                                                       final DateTime billingRequestedDateRaw,
+                                                       @Nullable final SubscriptionBase baseSubscription,
+                                                       final Catalog catalog,
+                                                       final InternalCallContext context) throws CatalogApiException, SubscriptionBaseApiException {
+        DateTime billingRequestedDate = billingRequestedDateRaw;
+        if (baseSubscription != null) {
+            final DateTime baseSubscriptionStartDate = getBaseSubscription(bundle.getId(), catalog, context).getStartDate();
+            billingRequestedDate = billingRequestedDateRaw.isBefore(baseSubscriptionStartDate) ? baseSubscriptionStartDate : billingRequestedDateRaw;
+        }
+        return billingRequestedDate;
+    }
+
+    private SubscriptionBaseBundle getBundleWithSanity(final SubscriptionBaseWithAddOnsSpecifier subscriptionBaseWithAddOnsSpecifier,
+                                                       final Catalog catalog,
+                                                       final TenantContext callContext,
+                                                       final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        SubscriptionBaseBundle bundle = null;
+        if (subscriptionBaseWithAddOnsSpecifier.getBundleId() != null) {
+            bundle = dao.getSubscriptionBundleFromId(subscriptionBaseWithAddOnsSpecifier.getBundleId(), context);
+            if (bundle == null ||
+                (subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey() != null && !subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey().equals(bundle.getExternalKey()))) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
+            }
+        } else if (subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey() != null) {
+            final SubscriptionBaseBundle tmp = getActiveBundleForKey(subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey(), catalog, context);
+            if (tmp != null && !tmp.getAccountId().equals(callContext.getAccountId())) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey());
+            } else {
+                bundle = tmp;
+            }
+        }
+        return bundle;
+    }
+
+    private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final SubscriptionBaseBundle bundle,
+                                                                             final boolean hasBaseOrStandalonePlanSpecifier,
+                                                                             final List<EntitlementSpecifier> entitlements,
+                                                                             final List<Plan> entitlementsPlans,
+                                                                             final boolean isMigrated,
+                                                                             final DateTime effectiveDate,
+                                                                             final Catalog catalog,
+                                                                             final AddonUtils addonUtils,
+                                                                             final TenantContext callContext,
+                                                                             final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
+        for (int i = 0; i < entitlements.size(); i++) {
+            final EntitlementSpecifier entitlement = entitlements.get(i);
+            final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
+            if (spec == null) {
+                // BP already exists
+                continue;
+            }
+
+            final Plan plan = entitlementsPlans.get(i);
+            final PlanPhase phase = plan.getAllPhases()[0];
+            if (phase == null) {
+                throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
+                                                              spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
+            }
+
+            // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
+            if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
+                if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
+                    // TODO We should also look to the specifiers being created for validation
+                    final List<DefaultSubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundle.getId(), null, catalog, addonUtils, callContext, context);
+                    final int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
+                    final int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlementsPlans, plan);
+                    if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
+                        // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
+                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
+                    }
+                }
+            }
+
+            final DateTime bundleStartDate;
+            if (hasBaseOrStandalonePlanSpecifier) {
+                bundleStartDate = effectiveDate;
+            } else {
+                final SubscriptionBase baseSubscription = dao.getBaseSubscription(bundle.getId(), catalog, context);
+                bundleStartDate = getBundleStartDateWithSanity(bundle.getId(), baseSubscription, plan, effectiveDate, addonUtils, context);
+            }
+
+            final SubscriptionSpecifier subscription = new SubscriptionSpecifier();
+            subscription.setRealPriceList(plan.getPriceListName());
+            subscription.setEffectiveDate(effectiveDate);
+            subscription.setProcessedDate(context.getCreatedDate());
+            subscription.setPlan(plan);
+            subscription.setInitialPhase(spec.getPhaseType());
+            subscription.setBuilder(new SubscriptionBuilder()
+                                            .setId(UUIDs.randomUUID())
+                                            .setBundleId(bundle.getId())
+                                            .setBundleExternalKey(bundle.getExternalKey())
+                                            .setCategory(plan.getProduct().getCategory())
+                                            .setBundleStartDate(bundleStartDate)
+                                            .setAlignStartDate(effectiveDate)
+                                            .setMigrated(isMigrated));
+
+            subscriptions.add(subscription);
+        }
+
+        return subscriptions;
+    }
+
+    private boolean createPlansIfNeededAndReorderBPOrStandaloneSpecFirstWithSanity(final SubscriptionBaseWithAddOnsSpecifier subscriptionBaseWithAddOnsSpecifier,
+                                                                                   final Catalog catalog,
+                                                                                   final DateTime effectiveDate,
+                                                                                   final Collection<EntitlementSpecifier> outputEntitlementSpecifier,
+                                                                                   final Collection<Plan> outputEntitlementPlans,
+                                                                                   final CallContext callContext) throws SubscriptionBaseApiException, CatalogApiException {
+        EntitlementSpecifier basePlanSpecifier = null;
+        Plan basePlan = null;
+        final Collection<EntitlementSpecifier> addOnSpecifiers = new ArrayList<EntitlementSpecifier>();
+        final Collection<EntitlementSpecifier> standaloneSpecifiers = new ArrayList<EntitlementSpecifier>();
+        final Collection<Plan> addOnsPlans = new ArrayList<Plan>();
+        final Collection<Plan> standalonePlans = new ArrayList<Plan>();
+
+        for (final EntitlementSpecifier cur : subscriptionBaseWithAddOnsSpecifier.getEntitlementSpecifiers()) {
+            final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(cur.getOverrides(), callContext);
+            // Called by createBaseSubscriptionsWithAddOns only -- no need for subscription start date
+            final Plan plan = catalog.createOrFindPlan(cur.getPlanPhaseSpecifier(), overridesWithContext, effectiveDate);
+
+            final boolean isBase = isBaseSpecifier(plan);
+            final boolean isStandalone = isStandaloneSpecifier(plan);
+            if (isStandalone) {
+                standaloneSpecifiers.add(cur);
+                standalonePlans.add(plan);
+            } else if (isBase) {
+                if (basePlanSpecifier == null) {
+                    basePlanSpecifier = cur;
+                    basePlan = plan;
+                } else {
+                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
+                }
+            } else {
+                addOnSpecifiers.add(cur);
+                addOnsPlans.add(plan);
+            }
+        }
+
+        if (basePlanSpecifier != null) {
+            outputEntitlementSpecifier.add(basePlanSpecifier);
+            outputEntitlementPlans.add(basePlan);
+        }
+        outputEntitlementSpecifier.addAll(addOnSpecifiers);
+        outputEntitlementPlans.addAll(addOnsPlans);
+
+        if (!outputEntitlementSpecifier.isEmpty() && !standaloneSpecifiers.isEmpty()) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
+        }
+
+        if (standaloneSpecifiers.isEmpty()) {
+            return basePlanSpecifier != null;
+        } else {
+            outputEntitlementSpecifier.addAll(standaloneSpecifiers);
+            outputEntitlementPlans.addAll(standalonePlans);
+            return true;
+        }
+    }
+
+    private boolean isBaseSpecifier(final Plan inputPlan) {
+        return inputPlan.getProduct().getCategory() == ProductCategory.BASE;
+    }
+
+    private boolean isStandaloneSpecifier(final Plan inputPlan) {
+        return inputPlan.getProduct().getCategory() == ProductCategory.STANDALONE;
+    }
+
+    private int countCurrentAddOnsWithSamePlanName(final Iterable<Plan> entitlementsPlans, final Plan currentPlan) {
+        int countCurrentAddOns = 0;
+        for (final Plan plan : entitlementsPlans) {
+            if (plan.getName().equalsIgnoreCase(currentPlan.getName())
+                && plan.getProduct().getCategory() != null
+                && ProductCategory.ADD_ON.equals(plan.getProduct().getCategory())) {
+                countCurrentAddOns++;
+            }
+        }
+        return countCurrentAddOns;
+    }
+}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index d5c4bb6..dfdb63e 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -20,7 +20,6 @@ package org.killbill.billing.subscription.api.svcs;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -41,19 +40,16 @@ import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogInternalApi;
 import org.killbill.billing.catalog.api.Plan;
-import org.killbill.billing.catalog.api.PlanChangeResult;
-import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun;
 import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun.DryRunChangeReason;
-import org.killbill.billing.entitlement.api.EntitlementSpecifier;
 import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
 import org.killbill.billing.invoice.api.DryRunArguments;
-import org.killbill.billing.subscription.api.SubscriptionApiBase;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseApiService;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
@@ -63,21 +59,17 @@ import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEv
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionStatusDryRun;
-import org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData;
 import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
-import org.killbill.billing.subscription.api.user.SubscriptionSpecifier;
 import org.killbill.billing.subscription.engine.addon.AddonUtils;
 import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
 import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
 import org.killbill.billing.subscription.events.bcd.BCDEvent;
 import org.killbill.billing.subscription.events.bcd.BCDEventData;
-import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
-import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.bcd.BillCycleDayCalculator;
 import org.killbill.billing.util.cache.AccountIdFromBundleIdCacheLoader;
 import org.killbill.billing.util.cache.BundleIdFromSubscriptionIdCacheLoader;
@@ -93,7 +85,6 @@ import org.killbill.billing.util.entity.Pagination;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
 import org.killbill.clock.Clock;
 import org.killbill.clock.DefaultClock;
-import org.killbill.notificationq.api.NotificationQueueService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -106,7 +97,7 @@ import com.google.inject.Inject;
 
 import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEntityPaginationNoException;
 
-public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implements SubscriptionBaseInternalApi {
+public class DefaultSubscriptionInternalApi extends DefaultSubscriptionBaseCreateApi implements SubscriptionBaseInternalApi {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionInternalApi.class);
 
@@ -133,7 +124,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     @Inject
     public DefaultSubscriptionInternalApi(final SubscriptionDao dao,
                                           final SubscriptionBaseApiService apiService,
-                                          final NotificationQueueService notificationQueueService,
                                           final Clock clock,
                                           final CatalogInternalApi catalogInternalApi,
                                           final AddonUtils addonUtils,
@@ -147,230 +137,25 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         this.bundleIdCacheController = cacheControllerDispatcher.getCacheController(CacheType.BUNDLE_ID_FROM_SUBSCRIPTION_ID);
     }
 
-    private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final SubscriptionBaseBundle bundle,
-                                                                             final boolean hasBaseOrStandalonePlanSpecifier,
-                                                                             final Iterable<EntitlementSpecifier> entitlements,
-                                                                             final boolean isMigrated,
-                                                                             final InternalCallContext context,
-                                                                             final DateTime now,
-                                                                             final DateTime effectiveDate,
-                                                                             final Catalog catalog,
-                                                                             final CallContext callContext) throws SubscriptionBaseApiException, CatalogApiException {
-        final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
-        for (final EntitlementSpecifier entitlement : entitlements) {
-            final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
-            if (spec == null) {
-                // BP already exists
-                continue;
-            }
-
-            final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
-
-            final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
-            final PlanPhase phase = plan.getAllPhases()[0];
-            if (phase == null) {
-                throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
-                                                              spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
-            }
-
-            // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
-            if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
-                if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
-                    // TODO We should also look to the specifiers being created for validation
-                    final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundle.getId(), null, context);
-                    final int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
-                    final int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
-                    if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
-                        // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
-                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
-                    }
-                }
-            }
-
-            final DateTime bundleStartDate;
-            if (hasBaseOrStandalonePlanSpecifier) {
-                bundleStartDate = effectiveDate;
-            } else {
-                final SubscriptionBase baseSubscription = dao.getBaseSubscription(bundle.getId(), catalog, context);
-                bundleStartDate = getBundleStartDateWithSanity(bundle.getId(), baseSubscription, plan, effectiveDate, catalog, context);
-            }
-
-            final SubscriptionSpecifier subscription = new SubscriptionSpecifier();
-            subscription.setRealPriceList(plan.getPriceListName());
-            subscription.setEffectiveDate(effectiveDate);
-            subscription.setProcessedDate(now);
-            subscription.setPlan(plan);
-            subscription.setInitialPhase(spec.getPhaseType());
-            subscription.setBuilder(new SubscriptionBuilder()
-                                            .setId(UUIDs.randomUUID())
-                                            .setBundleId(bundle.getId())
-                                            .setBundleExternalKey(bundle.getExternalKey())
-                                            .setCategory(plan.getProduct().getCategory())
-                                            .setBundleStartDate(bundleStartDate)
-                                            .setAlignStartDate(effectiveDate)
-                                            .setMigrated(isMigrated));
-
-            subscriptions.add(subscription);
-        }
-        return subscriptions;
-    }
-
-    private boolean sanityAndReorderBPOrStandaloneSpecFirst(final Catalog catalog,
-                                                            final SubscriptionBaseWithAddOnsSpecifier subscriptionBaseWithAddOnsSpecifier,
-                                                            final DateTime effectiveDate,
-                                                            final Collection<EntitlementSpecifier> outputEntitlementSpecifier) throws SubscriptionBaseApiException {
-        EntitlementSpecifier basePlanSpecifier = null;
-        final Collection<EntitlementSpecifier> addOnSpecifiers = new ArrayList<EntitlementSpecifier>();
-        final Collection<EntitlementSpecifier> standaloneSpecifiers = new ArrayList<EntitlementSpecifier>();
-        try {
-            for (final EntitlementSpecifier cur : subscriptionBaseWithAddOnsSpecifier.getEntitlementSpecifiers()) {
-                final boolean isBase = isBaseSpecifier(catalog, effectiveDate, cur);
-                final boolean isStandalone = isStandaloneSpecifier(catalog, effectiveDate, cur);
-                if (isStandalone) {
-                    standaloneSpecifiers.add(cur);
-                } else if (isBase) {
-                    if (basePlanSpecifier == null) {
-                        basePlanSpecifier = cur;
-                    } else {
-                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
-                    }
-                } else {
-                    addOnSpecifiers.add(cur);
-                }
-            }
-        } catch (final CatalogApiException e) {
-            throw new SubscriptionBaseApiException(e);
-        }
-
-        if (basePlanSpecifier != null) {
-            outputEntitlementSpecifier.add(basePlanSpecifier);
-        }
-        outputEntitlementSpecifier.addAll(addOnSpecifiers);
-
-        if (!outputEntitlementSpecifier.isEmpty() && !standaloneSpecifiers.isEmpty()) {
-            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
-        }
-
-        if (standaloneSpecifiers.isEmpty()) {
-            return basePlanSpecifier != null;
-        } else {
-            outputEntitlementSpecifier.addAll(standaloneSpecifiers);
-            return true;
-        }
-    }
-
-    private boolean isBaseSpecifier(final Catalog catalog, final DateTime effectiveDate, final EntitlementSpecifier cur) throws CatalogApiException {
-        final Plan inputPlan = catalog.createOrFindPlan(cur.getPlanPhaseSpecifier(), null, effectiveDate);
-        return inputPlan.getProduct().getCategory() == ProductCategory.BASE;
-    }
-
-    private boolean isStandaloneSpecifier(final Catalog catalog, final DateTime effectiveDate, final EntitlementSpecifier cur) throws CatalogApiException {
-        final Plan inputPlan = catalog.createOrFindPlan(cur.getPlanPhaseSpecifier(), null, effectiveDate);
-        return inputPlan.getProduct().getCategory() == ProductCategory.STANDALONE;
-    }
-
     @Override
     public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final Iterable<SubscriptionBaseWithAddOnsSpecifier> subscriptionWithAddOnsSpecifiers, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
         try {
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
             final CallContext callContext = internalCallContextFactory.createCallContext(context);
-            final UUID accountId = callContext.getAccountId();
-
-            final Collection<SubscriptionAndAddOnsSpecifier> subscriptionAndAddOns = new ArrayList<SubscriptionAndAddOnsSpecifier>();
-            for (final SubscriptionBaseWithAddOnsSpecifier subscriptionBaseWithAddOnsSpecifier : subscriptionWithAddOnsSpecifiers) {
-                final DateTime billingRequestedDateRaw = (subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate() != null) ?
-                                                         context.toUTCDateTime(subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate()) : context.getCreatedDate();
-
-                final Collection<EntitlementSpecifier> reorderedSpecifiers = new ArrayList<EntitlementSpecifier>();
-                // Note: billingRequestedDateRaw might not be accurate here (add-on with a too early date passed)?
-                final boolean hasBaseOrStandalonePlanSpecifier = sanityAndReorderBPOrStandaloneSpecFirst(catalog, subscriptionBaseWithAddOnsSpecifier, billingRequestedDateRaw, reorderedSpecifiers);
-
-                DateTime billingRequestedDate = billingRequestedDateRaw;
-                SubscriptionBaseBundle bundle = null;
-                if (subscriptionBaseWithAddOnsSpecifier.getBundleId() != null) {
-                    bundle = dao.getSubscriptionBundleFromId(subscriptionBaseWithAddOnsSpecifier.getBundleId(), context);
-                    if (bundle == null ||
-                        (subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey() != null && !subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey().equals(bundle.getExternalKey()))) {
-                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
-                    }
-                } else if (subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey() != null &&
-                           !hasBaseOrStandalonePlanSpecifier) { // Skip the expensive checks if we are about to create the bundle (validation will be done in SubscriptionDao#createSubscriptionBundle)
-                    final SubscriptionBaseBundle tmp = getActiveBundleForKey(subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey(), catalog, context);
-                    if (tmp == null) {
-                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BP, subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey());
-                    } else if (!tmp.getAccountId().equals(accountId)) {
-                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey());
-                    } else {
-                        bundle = tmp;
-                    }
-                }
 
-                SubscriptionBase baseSubscription = null;
-                if (bundle != null) {
-                    baseSubscription = dao.getBaseSubscription(bundle.getId(), catalog, context);
-                    if (baseSubscription != null) {
-                        final DateTime baseSubscriptionStartDate = getBaseSubscription(bundle.getId(), context).getStartDate();
-                        billingRequestedDate = billingRequestedDateRaw.isBefore(baseSubscriptionStartDate) ? baseSubscriptionStartDate : billingRequestedDateRaw;
-                    }
-                }
-
-                if (bundle == null && hasBaseOrStandalonePlanSpecifier) {
-                    bundle = createBundleForAccount(accountId,
-                                                    subscriptionBaseWithAddOnsSpecifier.getBundleExternalKey(),
-                                                    renameCancelledBundleIfExist,
-                                                    context);
-                } else if (bundle != null && baseSubscription != null && hasBaseOrStandalonePlanSpecifier) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundle.getExternalKey());
-                } else if (bundle == null) {
-                    log.warn("Invalid specifier: {}", subscriptionBaseWithAddOnsSpecifier);
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
-                }
-
-                final SubscriptionAndAddOnsSpecifier subscriptionAndAddOnsSpecifier = new SubscriptionAndAddOnsSpecifier(bundle,
-                                                                                                                         billingRequestedDate,
-                                                                                                                         verifyAndBuildSubscriptionSpecifiers(bundle,
-                                                                                                                                                              hasBaseOrStandalonePlanSpecifier,
-                                                                                                                                                              reorderedSpecifiers,
-                                                                                                                                                              subscriptionBaseWithAddOnsSpecifier.isMigrated(),
-                                                                                                                                                              context,
-                                                                                                                                                              context.getCreatedDate(),
-                                                                                                                                                              billingRequestedDate,
-                                                                                                                                                              catalog,
-                                                                                                                                                              callContext));
-                subscriptionAndAddOns.add(subscriptionAndAddOnsSpecifier);
-            }
-
-            final List<SubscriptionBaseWithAddOns> subscriptionBaseWithAddOns = apiService.createPlansWithAddOns(accountId, subscriptionAndAddOns, catalog, callContext);
-            for (final SubscriptionBaseWithAddOns subscriptionBaseWithAO : subscriptionBaseWithAddOns) {
-                for (final SubscriptionBase subscriptionBase : subscriptionBaseWithAO.getSubscriptionBaseList()) {
-                    bundleIdCacheController.putIfAbsent(subscriptionBase.getId(), subscriptionBaseWithAO.getBundle().getId());
-                }
-            }
-            return subscriptionBaseWithAddOns;
+            return super.createBaseSubscriptionsWithAddOns(subscriptionWithAddOnsSpecifiers,
+                                                           renameCancelledBundleIfExist,
+                                                           catalog,
+                                                           addonUtils,
+                                                           accountIdCacheController,
+                                                           bundleIdCacheController,
+                                                           callContext,
+                                                           context);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
 
-    private int countCurrentAddOnsWithSamePlanName(final Iterable<EntitlementSpecifier> entitlements,
-                                                   final Catalog catalog, final String planName,
-                                                   final DateTime effectiveDate, final CallContext callContext) throws CatalogApiException {
-        int countCurrentAddOns = 0;
-        for (final EntitlementSpecifier entitlement : entitlements) {
-            final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
-            final PlanPhasePriceOverridesWithCallContext overridesWithContext =
-                    new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
-            final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
-
-            if (plan.getName().equalsIgnoreCase(planName)
-                && plan.getProduct().getCategory() != null
-                && ProductCategory.ADD_ON.equals(plan.getProduct().getCategory())) {
-                countCurrentAddOns++;
-            }
-        }
-        return countCurrentAddOns;
-    }
-
     @Override
     public void cancelBaseSubscriptions(final Iterable<SubscriptionBase> subscriptions, final BillingActionPolicy policy, int accountBillCycleDayLocal, final InternalCallContext context) throws SubscriptionBaseApiException {
 
@@ -407,9 +192,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         }
         try {
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
-            final SubscriptionBaseBundle subscriptionBundle = dao.createSubscriptionBundle(bundle, catalog, renameCancelledBundleIfExist, context);
-            accountIdCacheController.putIfAbsent(bundle.getId(), accountId);
-            return subscriptionBundle;
+            return super.createBundleForAccount(accountId, bundleKey, renameCancelledBundleIfExist, catalog, accountIdCacheController, context);
         } catch (final CatalogApiException e) {
             throw new  SubscriptionBaseApiException(e);
         }
@@ -475,48 +258,23 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     @Override
     public SubscriptionBaseBundle getActiveBundleForKey(final String bundleKey, final Catalog catalog, final InternalTenantContext context) {
-        final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(bundleKey, context);
-        for (final SubscriptionBaseBundle cur : existingBundles) {
-            final List<SubscriptionBase> subscriptions;
-            try {
-                subscriptions = dao.getSubscriptions(cur.getId(), ImmutableList.<SubscriptionBaseEvent>of(), catalog, context);
-                for (final SubscriptionBase s : subscriptions) {
-                    if (s.getCategory() == ProductCategory.ADD_ON) {
-                        continue;
-                    }
-                    if (s.getEndDate() == null || s.getEndDate().compareTo(clock.getUTCNow()) > 0) {
-                        return cur;
-                    }
-                }
-            } catch (final CatalogApiException e) {
-                log.warn("Failed to get subscriptions for bundleId='{}'", cur.getId(), e);
-                return null;
-            }
+        try {
+            return super.getActiveBundleForKey(bundleKey, catalog, context);
+        } catch (final CatalogApiException e) {
+            log.warn("Failed to get subscriptions", e);
+            return null;
         }
-        return null;
     }
 
     @Override
     public List<SubscriptionBase> getSubscriptionsForBundle(final UUID bundleId,
                                                             @Nullable final DryRunArguments dryRunArguments,
                                                             final InternalTenantContext context) throws SubscriptionBaseApiException {
-
         try {
-
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
-
-            final List<SubscriptionBaseEvent> outputDryRunEvents = new ArrayList<SubscriptionBaseEvent>();
-            final List<SubscriptionBase> outputSubscriptions = new ArrayList<SubscriptionBase>();
-
-            populateDryRunEvents(bundleId, dryRunArguments, outputDryRunEvents, outputSubscriptions, catalog, context);
-            final List<SubscriptionBase> result;
-            result = dao.getSubscriptions(bundleId, outputDryRunEvents, catalog, context);
-            if (result != null && !result.isEmpty()) {
-                outputSubscriptions.addAll(result);
-            }
-            Collections.sort(outputSubscriptions, DefaultSubscriptionInternalApi.SUBSCRIPTIONS_COMPARATOR);
-
-            return createSubscriptionsForApiUse(outputSubscriptions);
+            final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
+            final List<DefaultSubscriptionBase> subscriptionsForBundle = super.getSubscriptionsForBundle(bundleId, dryRunArguments, catalog, addonUtils, tenantContext, context);
+            return new ArrayList<SubscriptionBase>(subscriptionsForBundle);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -525,10 +283,11 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     @Override
     public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, final InternalTenantContext context) throws SubscriptionBaseApiException {
         try {
-            final Map<UUID, List<SubscriptionBase>> internalSubscriptions = dao.getSubscriptionsForAccount(catalog, context);
+            final Map<UUID, List<DefaultSubscriptionBase>> internalSubscriptions = dao.getSubscriptionsForAccount(catalog, context);
             final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
             for (final UUID bundleId : internalSubscriptions.keySet()) {
-                result.put(bundleId, createSubscriptionsForApiUse(internalSubscriptions.get(bundleId)));
+                final List<DefaultSubscriptionBase> subscriptionsForApiUse = createSubscriptionsForApiUse(internalSubscriptions.get(bundleId));
+                result.put(bundleId, new ArrayList<SubscriptionBase>(subscriptionsForApiUse));
             }
             return result;
         } catch (final CatalogApiException e) {
@@ -540,12 +299,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     public SubscriptionBase getBaseSubscription(final UUID bundleId, final InternalTenantContext context) throws SubscriptionBaseApiException {
         try {
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
-
-            final SubscriptionBase result = dao.getBaseSubscription(bundleId, catalog, context);
-            if (result == null) {
-                throw new SubscriptionBaseApiException(ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
-            }
-            return createSubscriptionForApiUse(result);
+            return super.getBaseSubscription(bundleId, catalog, context);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -619,11 +373,11 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : null;
         final DateTime effectiveCatalogDate = effectiveDate != null ? effectiveDate : context.getCreatedDate();
         final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
-        final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveCatalogDate);
+        final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveCatalogDate, subscription.getStartDate());
         if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
             if (plan.getPlansAllowedInBundle() != -1
                 && plan.getPlansAllowedInBundle() > 0
-                && addonUtils.countExistingAddOnsWithSamePlanName(getSubscriptionsForBundle(subscription.getBundleId(), null, context), plan.getName())
+                && addonUtils.countExistingAddOnsWithSamePlanName(getSubscriptionsForBundle(subscription.getBundleId(), null, catalog, addonUtils, callContext, context), plan.getName())
                    >= plan.getPlansAllowedInBundle()) {
                 // the plan can be changed to the new value, because it has reached its limit by bundle
                 throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
@@ -648,7 +402,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
             final List<EntitlementAOStatusDryRun> result = new LinkedList<EntitlementAOStatusDryRun>();
 
-            final List<SubscriptionBase> bundleSubscriptions = dao.getSubscriptions(subscription.getBundleId(), ImmutableList.<SubscriptionBaseEvent>of(), catalog, context);
+            final List<DefaultSubscriptionBase> bundleSubscriptions = dao.getSubscriptions(subscription.getBundleId(), ImmutableList.<SubscriptionBaseEvent>of(), catalog, context);
             for (final SubscriptionBase cur : bundleSubscriptions) {
                 if (cur.getId().equals(subscriptionId)) {
                     continue;
@@ -659,11 +413,13 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                     continue;
                 }
 
+                final Product baseProduct = baseProductName != null ? catalog.findProduct(baseProductName, requestedDate) : null;
+
                 final DryRunChangeReason reason;
                 // If baseProductName is null, it's a cancellation dry-run. In this case, return all addons, so they are cancelled
-                if (baseProductName != null && addonUtils.isAddonIncludedFromProdName(baseProductName, cur.getCurrentPlan(), requestedDate, catalog, context)) {
+                if (baseProduct != null && addonUtils.isAddonIncluded(baseProduct, cur.getCurrentPlan())) {
                     reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
-                } else if (baseProductName != null && addonUtils.isAddonAvailableFromProdName(baseProductName, cur.getCurrentPlan(), requestedDate, catalog, context)) {
+                } else if (baseProduct != null && addonUtils.isAddonAvailable(baseProduct, cur.getCurrentPlan())) {
                     reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
                 } else {
                     reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
@@ -679,7 +435,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
-
     }
 
     @Override
@@ -687,111 +442,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         dao.updateBundleExternalKey(bundleId, newExternalKey, context);
     }
 
-    private void populateDryRunEvents(@Nullable final UUID bundleId,
-                                      @Nullable final DryRunArguments dryRunArguments,
-                                      final Collection<SubscriptionBaseEvent> outputDryRunEvents,
-                                      final Collection<SubscriptionBase> outputSubscriptions,
-                                      final Catalog catalog,
-                                      final InternalTenantContext context) throws SubscriptionBaseApiException {
-        if (dryRunArguments == null || dryRunArguments.getAction() == null) {
-            return;
-        }
-
-        final DateTime utcNow = clock.getUTCNow();
-        List<SubscriptionBaseEvent> dryRunEvents = null;
-        try {
-            final PlanPhaseSpecifier inputSpec = dryRunArguments.getPlanPhaseSpecifier();
-            final boolean isInputSpecNullOrEmpty = inputSpec == null ||
-                                                   (inputSpec.getPlanName() == null && inputSpec.getProductName() == null && inputSpec.getBillingPeriod() == null);
-
-            // Create an overridesWithContext with a null context to indicate this is dryRun and no price overriden plan should be created.
-            final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(dryRunArguments.getPlanPhasePriceOverrides(), null);
-            final Plan plan = isInputSpecNullOrEmpty ?
-                              null :
-                              catalog.createOrFindPlan(inputSpec, overridesWithContext, utcNow);
-            final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
-
-            switch (dryRunArguments.getAction()) {
-                case START_BILLING:
-
-                    final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, catalog, context);
-                    final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
-                    final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, catalog, context);
-                    final UUID subscriptionId = UUIDs.randomUUID();
-                    dryRunEvents = apiService.getEventsOnCreation(subscriptionId, startEffectiveDate, bundleStartDate, plan, inputSpec.getPhaseType(), plan.getPriceListName(),
-                                                                  startEffectiveDate, catalog, context);
-                    final SubscriptionBuilder builder = new SubscriptionBuilder()
-                            .setId(subscriptionId)
-                            .setBundleId(bundleId)
-                            .setBundleExternalKey(null)
-                            .setCategory(plan.getProduct().getCategory())
-                            .setBundleStartDate(bundleStartDate)
-                            .setAlignStartDate(startEffectiveDate);
-                    final DefaultSubscriptionBase newSubscription = new DefaultSubscriptionBase(builder, apiService, clock);
-                    newSubscription.rebuildTransitions(dryRunEvents, catalog);
-                    outputSubscriptions.add(newSubscription);
-                    break;
-
-                case CHANGE:
-                    final DefaultSubscriptionBase subscriptionForChange = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), catalog, context);
-
-                    DateTime changeEffectiveDate = getDryRunEffectiveDate(dryRunArguments.getEffectiveDate(), subscriptionForChange, context);
-                    if (changeEffectiveDate == null) {
-                        BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
-                        if (policy == null) {
-                            final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange, inputSpec, utcNow, tenantContext);
-                            policy = planChangeResult.getPolicy();
-                        }
-                        // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
-                        changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy, null, -1, context);
-                    }
-                    dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, plan.getPriceListName(), changeEffectiveDate, true, catalog, context);
-                    break;
-
-                case STOP_BILLING:
-                    final DefaultSubscriptionBase subscriptionForCancellation = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), catalog, context);
-
-                    DateTime cancelEffectiveDate = getDryRunEffectiveDate(dryRunArguments.getEffectiveDate(), subscriptionForCancellation, context);
-                    if (dryRunArguments.getEffectiveDate() == null) {
-                        BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
-                        if (policy == null) {
-                            final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
-                            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getName(),
-                                                                                   subscriptionForCancellation.getCurrentPhase().getPhaseType());
-                            policy = catalog.planCancelPolicy(spec, subscriptionForCancellation.getStartDate());
-                        }
-                        // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
-                        cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy, null, -1, context);
-                    }
-                    dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, true, catalog, context);
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Unexpected dryRunArguments action " + dryRunArguments.getAction());
-            }
-        } catch (final CatalogApiException e) {
-            throw new SubscriptionBaseApiException(e);
-        }
-        if (dryRunEvents != null && !dryRunEvents.isEmpty()) {
-            outputDryRunEvents.addAll(dryRunEvents);
-        }
-    }
-
-    private DateTime getDryRunEffectiveDate(@Nullable final LocalDate inputDate, final DefaultSubscriptionBase subscription, final InternalTenantContext context) {
-        if (inputDate == null) {
-            return null;
-        }
-
-        // We first use context account reference time to get a candidate)
-        final DateTime tmp = context.toUTCDateTime(inputDate);
-        // If we realize that the candidate is on the same LocalDate boundary as the subscription startDate but a bit prior we correct it to avoid weird things down the line
-        if (inputDate.compareTo(context.toLocalDate(subscription.getStartDate())) == 0 && tmp.compareTo(subscription.getStartDate()) < 0) {
-            return subscription.getStartDate();
-        } else {
-            return tmp;
-        }
-    }
-
     @Override
     public void updateBCD(final UUID subscriptionId, final int bcd, @Nullable final LocalDate effectiveFromDate, final InternalCallContext internalCallContext) throws SubscriptionBaseApiException {
 
@@ -810,7 +460,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     @Override
     public int getDefaultBillCycleDayLocal(final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final PlanPhaseSpecifier planPhaseSpecifier, final int accountBillCycleDayLocal, final Catalog catalog, final InternalTenantContext context) throws SubscriptionBaseApiException {
         try {
-            final BillingAlignment alignment = catalog.billingAlignment(planPhaseSpecifier, subscription.getStartDate());
+            final BillingAlignment alignment = catalog.billingAlignment(planPhaseSpecifier, clock.getUTCNow(), subscription.getStartDate());
             return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, context, accountBillCycleDayLocal);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
@@ -903,39 +553,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         return requestedDate == null ? internalCallContext.getCreatedDate() : internalCallContext.toUTCDateTime(requestedDate);
     }
 
-    private DateTime getBundleStartDateWithSanity(final UUID bundleId, @Nullable final SubscriptionBase baseSubscription, final Plan plan,
-                                                  final DateTime effectiveDate, final Catalog catalog, final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
-        switch (plan.getProduct().getCategory()) {
-            case BASE:
-                if (baseSubscription != null &&
-                    (baseSubscription.getState() == EntitlementState.ACTIVE || baseSubscription.getState() == EntitlementState.PENDING)) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
-                }
-                return effectiveDate;
-
-            case ADD_ON:
-                if (baseSubscription == null) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BP, bundleId);
-                }
-                if (effectiveDate.isBefore(baseSubscription.getStartDate())) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, effectiveDate.toString(), baseSubscription.getStartDate().toString());
-                }
-                addonUtils.checkAddonCreationRights(baseSubscription, plan, effectiveDate, catalog, context);
-                return baseSubscription.getStartDate();
-
-            case STANDALONE:
-                if (baseSubscription != null) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
-                }
-                // Not really but we don't care, there is no alignment for STANDALONE subscriptions
-                return effectiveDate;
-
-            default:
-                throw new SubscriptionBaseError(String.format("Can't create subscription of type %s",
-                                                              plan.getProduct().getCategory().toString()));
-        }
-    }
-
     private List<EffectiveSubscriptionInternalEvent> convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(final SubscriptionBase subscription,
                                                                                                                           final InternalTenantContext context, final Collection<SubscriptionBaseTransition> transitions) {
         return ImmutableList.<EffectiveSubscriptionInternalEvent>copyOf(Collections2.transform(transitions, new Function<SubscriptionBaseTransition, EffectiveSubscriptionInternalEvent>() {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
index 2ee1a66..b75e77f 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
@@ -68,10 +68,10 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
 
             final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(bundle.getAccountId(), context);
             final Catalog fullCatalog = catalogInternalApi.getFullCatalog(true, true, internalTenantContext);
-            final List<SubscriptionBase> subscriptions = dao.getSubscriptions(bundle.getId(),
-                                                                              ImmutableList.<SubscriptionBaseEvent>of(),
-                                                                              fullCatalog,
-                                                                              internalTenantContext);
+            final List<DefaultSubscriptionBase> subscriptions = dao.getSubscriptions(bundle.getId(),
+                                                                                     ImmutableList.<SubscriptionBaseEvent>of(),
+                                                                                     fullCatalog,
+                                                                                     internalTenantContext);
             if (subscriptions.size() == 0) {
                 throw new SubscriptionBaseRepairException(ErrorCode.SUB_NO_ACTIVE_SUBSCRIPTIONS, bundle.getId());
             }
@@ -83,7 +83,7 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
         }
     }
 
-    private String getViewId(final DateTime lastUpdateBundleDate, final List<SubscriptionBase> subscriptions) {
+    private String getViewId(final DateTime lastUpdateBundleDate, final List<DefaultSubscriptionBase> subscriptions) {
         final StringBuilder tmp = new StringBuilder();
         long lastOrderedId = -1;
         for (final SubscriptionBase cur : subscriptions) {
@@ -130,7 +130,7 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
         };
     }
 
-    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionBase> subscriptions, final List<SubscriptionBaseTimeline> inRepair, final Catalog fullCatalog, final InternalTenantContext tenantContext) throws CatalogApiException {
+    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionBaseTimeline> inRepair, final Catalog fullCatalog, final InternalTenantContext tenantContext) throws CatalogApiException {
 
         final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
         final Set<UUID> repairIds = new TreeSet<UUID>();
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 6f3b516..9273757 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -174,7 +174,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         try {
             final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
             final Catalog fullCatalog = catalogInternalApi.getFullCatalog(true, true, internalCallContext);
-            final BillingActionPolicy policy = fullCatalog.planCancelPolicy(planPhase, subscription.getStartDate());
+            final BillingActionPolicy policy = fullCatalog.planCancelPolicy(planPhase, clock.getUTCNow(), subscription.getStartDate());
 
             Preconditions.checkState(policy != BillingActionPolicy.START_OF_TERM, "A default START_OF_TERM policy is not availaible");
 
@@ -227,7 +227,9 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         try {
             for (final DefaultSubscriptionBase subscription : subscriptions) {
-                final BillingAlignment billingAlignment = (subscription.getState() == EntitlementState.PENDING ? null : catalog.billingAlignment(new PlanPhaseSpecifier(subscription.getLastActivePlan().getName(), subscription.getLastActivePhase().getPhaseType()), subscription.getStartDate()));
+                final BillingAlignment billingAlignment = (subscription.getState() == EntitlementState.PENDING ? null : catalog.billingAlignment(new PlanPhaseSpecifier(subscription.getLastActivePlan().getName(), subscription.getLastActivePhase().getPhaseType()),
+                                                                                                                                                 clock.getUTCNow(),
+                                                                                                                                                 subscription.getStartDate()));
                 final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, billingAlignment, accountBillCycleDayLocal, context);
                 subscriptionsWithEffectiveDate.put(subscription, effectiveDate);
             }
@@ -389,7 +391,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getName(),
                                                                             subscription.getCurrentOrPendingPhase().getPhaseType());
-            planChangeResult = catalogInternalApi.getFullCatalog(true, true, internalCallContext).planChange(fromPlanPhase, toPlanPhase, subscription.getStartDate());
+            planChangeResult = catalogInternalApi.getFullCatalog(true, true, internalCallContext).planChange(fromPlanPhase, toPlanPhase, effectiveDate, subscription.getStartDate());
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -606,7 +608,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         }
     }
 
-    private List<DefaultSubscriptionBase> computeAddOnsToCancel(final Collection<SubscriptionBaseEvent> cancelEvents, final CatalogEntity baseProduct, final UUID bundleId, final DateTime effectiveDate, final Catalog catalog, final InternalCallContext internalCallContext) throws CatalogApiException {
+    private List<DefaultSubscriptionBase> computeAddOnsToCancel(final Collection<SubscriptionBaseEvent> cancelEvents, final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final Catalog catalog, final InternalCallContext internalCallContext) throws CatalogApiException {
         // If cancellation/change occur in the future, there is nothing to do
         if (effectiveDate.compareTo(internalCallContext.getCreatedDate()) > 0) {
             return ImmutableList.<DefaultSubscriptionBase>of();
@@ -615,12 +617,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         }
     }
 
-    private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(final Collection<SubscriptionBaseEvent> events, final CatalogEntity baseProduct, final UUID bundleId,
+    private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(final Collection<SubscriptionBaseEvent> events, final Product baseProduct, final UUID bundleId,
                                                                                   final DateTime effectiveDate, final Catalog catalog, final InternalTenantContext internalTenantContext) throws CatalogApiException {
 
         final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
 
-        final List<SubscriptionBase> subscriptions = dao.getSubscriptions(bundleId, ImmutableList.<SubscriptionBaseEvent>of(), catalog, internalTenantContext);
+        final List<DefaultSubscriptionBase> subscriptions = dao.getSubscriptions(bundleId, ImmutableList.<SubscriptionBaseEvent>of(), catalog, internalTenantContext);
 
         for (final SubscriptionBase subscription : subscriptions) {
             final DefaultSubscriptionBase cur = (DefaultSubscriptionBase) subscription;
@@ -631,8 +633,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             final Plan addonCurrentPlan = cur.getCurrentPlan();
             if (baseProduct == null ||
-                addonUtils.isAddonIncludedFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, catalog, internalTenantContext) ||
-                !addonUtils.isAddonAvailableFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, catalog, internalTenantContext)) {
+                addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
+                !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
                 //
                 // Perform AO cancellation using the effectiveDate of the BP
                 //
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
index 587e1b7..da8dd4c 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
@@ -19,14 +19,10 @@
 package org.killbill.billing.subscription.engine.addon;
 
 import java.util.Collection;
-import java.util.List;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.catalog.api.Catalog;
-import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.CatalogInternalApi;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
@@ -34,27 +30,18 @@ import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
-import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
-
-import com.google.inject.Inject;
 
 public class AddonUtils {
 
-
-    @Inject
-    public AddonUtils() {
-    }
-
-    public void checkAddonCreationRights(final SubscriptionBase baseSubscription, final Plan targetAddOnPlan, final DateTime requestedDate, final Catalog catalog, final InternalTenantContext context)
-            throws SubscriptionBaseApiException, CatalogApiException {
-
+    public void checkAddonCreationRights(final SubscriptionBase baseSubscription, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context)
+            throws SubscriptionBaseApiException {
         if (baseSubscription.getState() == EntitlementState.CANCELLED ||
             (baseSubscription.getState() == EntitlementState.PENDING && context.toLocalDate(baseSubscription.getStartDate()).compareTo(context.toLocalDate(requestedDate)) < 0)) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_BP_NON_ACTIVE, targetAddOnPlan.getName());
         }
 
         final Plan currentOrPendingPlan = baseSubscription.getCurrentOrPendingPlan();
-        final Product baseProduct = catalog.findProduct(currentOrPendingPlan.getProduct().getName(), requestedDate);
+        final Product baseProduct = currentOrPendingPlan.getProduct();
         if (isAddonIncluded(baseProduct, targetAddOnPlan)) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_ALREADY_INCLUDED,
                                                    targetAddOnPlan.getName(), currentOrPendingPlan.getProduct().getName());
@@ -66,46 +53,7 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonAvailableFromProdName(final String baseProductName, final Plan targetAddOnPlan, final DateTime requestedDate, final Catalog catalog, final InternalTenantContext context) {
-        try {
-            final Product product = catalog.findProduct(baseProductName, requestedDate);
-            return isAddonAvailable(product, targetAddOnPlan);
-        } catch (CatalogApiException e) {
-            throw new SubscriptionBaseError(e);
-        }
-    }
-
-    public boolean isAddonAvailableFromPlanName(final String basePlanName, final Plan targetAddOnPlan, final DateTime requestedDate, final Catalog catalog, final InternalTenantContext context) {
-        try {
-            final Plan plan = catalog.findPlan(basePlanName, requestedDate);
-            final Product product = plan.getProduct();
-            return isAddonAvailable(product, targetAddOnPlan);
-        } catch (CatalogApiException e) {
-            throw new SubscriptionBaseError(e);
-        }
-    }
-
-    public boolean isAddonIncludedFromProdName(final String baseProductName, final Plan targetAddOnPlan, final DateTime requestedDate, final Catalog catalog, final InternalTenantContext context) {
-        try {
-            final Product product = catalog.findProduct(baseProductName, requestedDate);
-            return isAddonIncluded(product, targetAddOnPlan);
-        } catch (CatalogApiException e) {
-            throw new SubscriptionBaseError(e);
-        }
-
-    }
-
-    public boolean isAddonIncludedFromPlanName(final String basePlanName, final Plan targetAddOnPlan, final DateTime requestedDate, final Catalog catalog, final InternalTenantContext context) {
-        try {
-            final Plan plan = catalog.findPlan(basePlanName, requestedDate);
-            final Product product = plan.getProduct();
-            return isAddonIncluded(product, targetAddOnPlan);
-        } catch (CatalogApiException e) {
-            throw new SubscriptionBaseError(e);
-        }
-    }
-
-    private boolean isAddonAvailable(final Product baseProduct, final Plan targetAddOnPlan) {
+    public boolean isAddonAvailable(final Product baseProduct, final Plan targetAddOnPlan) {
         final Product targetAddonProduct = targetAddOnPlan.getProduct();
         final Collection<Product> availableAddOns = baseProduct.getAvailable();
 
@@ -117,7 +65,7 @@ public class AddonUtils {
         return false;
     }
 
-    private boolean isAddonIncluded(final Product baseProduct, final Plan targetAddOnPlan) {
+    public boolean isAddonIncluded(final Product baseProduct, final Plan targetAddOnPlan) {
         final Product targetAddonProduct = targetAddOnPlan.getProduct();
         final Collection<Product> includedAddOns = baseProduct.getIncluded();
         for (final Product curAv : includedAddOns) {
@@ -128,7 +76,7 @@ public class AddonUtils {
         return false;
     }
 
-    public int countExistingAddOnsWithSamePlanName(final Iterable<SubscriptionBase> subscriptionsForBundle, final String planName) {
+    public int countExistingAddOnsWithSamePlanName(final Iterable<DefaultSubscriptionBase> subscriptionsForBundle, final String planName) {
         int countExistingAddOns = 0;
         for (final SubscriptionBase subscription : subscriptionsForBundle) {
             if (subscription.getCurrentPlan().getName().equalsIgnoreCase(planName)
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 98ed638..2277355 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -43,6 +43,7 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.SubscriptionApiException;
@@ -351,9 +352,9 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public SubscriptionBase getSubscriptionFromId(final UUID subscriptionId, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
-        final SubscriptionBase shellSubscription = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<SubscriptionBase>() {
+        final DefaultSubscriptionBase shellSubscription = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<DefaultSubscriptionBase>() {
             @Override
-            public SubscriptionBase inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+            public DefaultSubscriptionBase inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionModelDao subscriptionModel = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getById(subscriptionId.toString(), context);
                 final SubscriptionBundleModelDao bundleModel = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getById(subscriptionModel.getBundleId().toString(), context);
                 return SubscriptionModelDao.toSubscription(subscriptionModel, bundleModel.getExternalKey());
@@ -374,21 +375,21 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+    public List<DefaultSubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
         return buildBundleSubscriptions(getSubscriptionFromBundleId(bundleId, context), null, dryRunEvents, catalog, context);
     }
 
-    private List<SubscriptionBase> getSubscriptionFromBundleId(final UUID bundleId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
+    private List<DefaultSubscriptionBase> getSubscriptionFromBundleId(final UUID bundleId, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<DefaultSubscriptionBase>>() {
             @Override
-            public List<SubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+            public List<DefaultSubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
                 final SubscriptionBundleModelDao bundleModel = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getById(bundleId.toString(), context);
 
                 final List<SubscriptionModelDao> models = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getSubscriptionsFromBundleId(bundleId.toString(), context);
-                return new ArrayList<SubscriptionBase>(Collections2.transform(models, new Function<SubscriptionModelDao, SubscriptionBase>() {
+                return new ArrayList<DefaultSubscriptionBase>(Collections2.transform(models, new Function<SubscriptionModelDao, DefaultSubscriptionBase>() {
                     @Override
-                    public SubscriptionBase apply(@Nullable final SubscriptionModelDao input) {
+                    public DefaultSubscriptionBase apply(@Nullable final SubscriptionModelDao input) {
                         return SubscriptionModelDao.toSubscription(input, bundleModel.getExternalKey());
                     }
                 }));
@@ -397,15 +398,15 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
-        final Map<UUID, List<SubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
+    public Map<UUID, List<DefaultSubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+        final Map<UUID, List<DefaultSubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
 
         final List<SubscriptionBaseEvent> eventsForAccount = getEventsForAccountId(context);
 
-        final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
+        final Map<UUID, List<DefaultSubscriptionBase>> result = new HashMap<UUID, List<DefaultSubscriptionBase>>();
         for (final UUID bundleId : subscriptionsFromAccountId.keySet()) {
 
-            final List<SubscriptionBase> subscriptionsForBundle = subscriptionsFromAccountId.get(bundleId);
+            final List<DefaultSubscriptionBase> subscriptionsForBundle = subscriptionsFromAccountId.get(bundleId);
             final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscriptions = ArrayListMultimap.create();
 
             for (final SubscriptionBase cur : subscriptionsForBundle) {
@@ -424,17 +425,17 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         return result;
     }
 
-    private Map<UUID, List<SubscriptionBase>> getSubscriptionsFromAccountId(final InternalTenantContext context) {
-        final List<SubscriptionBase> allSubscriptions = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
+    private Map<UUID, List<DefaultSubscriptionBase>> getSubscriptionsFromAccountId(final InternalTenantContext context) {
+        final List<DefaultSubscriptionBase> allSubscriptions = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<DefaultSubscriptionBase>>() {
             @Override
-            public List<SubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+            public List<DefaultSubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
                 final List<SubscriptionBundleModelDao> bundleModels = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getByAccountRecordId(context);
 
                 final List<SubscriptionModelDao> subscriptionModels = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getByAccountRecordId(context);
-                return new ArrayList<SubscriptionBase>(Collections2.transform(subscriptionModels, new Function<SubscriptionModelDao, SubscriptionBase>() {
+                return new ArrayList<DefaultSubscriptionBase>(Collections2.transform(subscriptionModels, new Function<SubscriptionModelDao, DefaultSubscriptionBase>() {
                     @Override
-                    public SubscriptionBase apply(final SubscriptionModelDao input) {
+                    public DefaultSubscriptionBase apply(final SubscriptionModelDao input) {
                         final SubscriptionBundleModelDao bundleModel = Iterables.find(bundleModels, new Predicate<SubscriptionBundleModelDao>() {
                             @Override
                             public boolean apply(final SubscriptionBundleModelDao bundleInput) {
@@ -447,10 +448,10 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
             }
         });
 
-        final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
-        for (final SubscriptionBase subscriptionBase : allSubscriptions) {
+        final Map<UUID, List<DefaultSubscriptionBase>> result = new HashMap<UUID, List<DefaultSubscriptionBase>>();
+        for (final DefaultSubscriptionBase subscriptionBase : allSubscriptions) {
             if (result.get(subscriptionBase.getBundleId()) == null) {
-                result.put(subscriptionBase.getBundleId(), new LinkedList<SubscriptionBase>());
+                result.put(subscriptionBase.getBundleId(), new LinkedList<DefaultSubscriptionBase>());
             }
             result.get(subscriptionBase.getBundleId()).add(subscriptionBase);
         }
@@ -836,14 +837,14 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         }
     }
 
-    private SubscriptionBase buildSubscription(final SubscriptionBase input, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+    private DefaultSubscriptionBase buildSubscription(final DefaultSubscriptionBase input, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
 
         if (input == null) {
             return null;
         }
-        final List<SubscriptionBase> bundleInput = new ArrayList<SubscriptionBase>();
+        final List<DefaultSubscriptionBase> bundleInput = new ArrayList<DefaultSubscriptionBase>();
         if (input.getCategory() == ProductCategory.ADD_ON) {
-            final SubscriptionBase baseSubscription = getBaseSubscription(input.getBundleId(), false, catalog, context);
+            final DefaultSubscriptionBase baseSubscription = getBaseSubscription(input.getBundleId(), false, catalog, context);
             if (baseSubscription == null) {
                 return null;
             }
@@ -854,8 +855,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
             bundleInput.add(input);
         }
 
-        final List<SubscriptionBase> reloadedSubscriptions = buildBundleSubscriptions(bundleInput, null, null, catalog, context);
-        for (final SubscriptionBase cur : reloadedSubscriptions) {
+        final List<DefaultSubscriptionBase> reloadedSubscriptions = buildBundleSubscriptions(bundleInput, null, null, catalog, context);
+        for (final DefaultSubscriptionBase cur : reloadedSubscriptions) {
             if (cur.getId().equals(input.getId())) {
                 return cur;
             }
@@ -864,7 +865,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         throw new SubscriptionBaseError("Unexpected code path in buildSubscription");
     }
 
-    private List<SubscriptionBase> buildBundleSubscriptions(final List<SubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription,
+    private List<DefaultSubscriptionBase> buildBundleSubscriptions(final List<DefaultSubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription,
                                                             @Nullable final Collection<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
         if (input == null || input.isEmpty()) {
             return Collections.emptyList();
@@ -875,14 +876,14 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
         final Collection<ApiEventChange> baseChangeEvents = new LinkedList<ApiEventChange>();
         ApiEventCancel baseCancellationEvent = null;
-        final List<SubscriptionBase> result = new ArrayList<SubscriptionBase>(input.size());
-        for (final SubscriptionBase cur : input) {
+        final List<DefaultSubscriptionBase> result = new ArrayList<DefaultSubscriptionBase>(input.size());
+        for (final DefaultSubscriptionBase cur : input) {
             final List<SubscriptionBaseEvent> events = eventsForSubscription != null ?
                                                        (List<SubscriptionBaseEvent>) eventsForSubscription.get(cur.getId()) :
                                                        getEventsForSubscription(cur.getId(), context);
             mergeDryRunEvents(cur.getId(), events, dryRunEvents);
 
-            SubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events, catalog, context);
+            DefaultSubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events, catalog, context);
 
             switch (cur.getCategory()) {
                 case BASE:
@@ -908,10 +909,11 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
                     SubscriptionBaseEvent baseTriggerEventForAddOnCancellation = baseCancellationEvent;
                     for (final ApiEventChange baseChangeEvent : baseChangeEvents) {
-                        final String baseProductName = baseChangeEvent.getEventPlan();
+                        final Plan basePlan = catalog.findPlan(baseChangeEvent.getEventPlan(), baseChangeEvent.getEffectiveDate(), cur.getAlignStartDate());
+                        final Product baseProduct = basePlan.getProduct();
 
-                        if ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), catalog, context)) ||
-                            (addonUtils.isAddonIncludedFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), catalog, context))) {
+                        if ((!addonUtils.isAddonAvailable(baseProduct, targetAddOnPlan)) ||
+                            (addonUtils.isAddonIncluded(baseProduct, targetAddOnPlan))) {
                             if (baseTriggerEventForAddOnCancellation != null) {
                                 if (baseTriggerEventForAddOnCancellation.getEffectiveDate().isAfter(baseChangeEvent.getEffectiveDate())) {
                                     baseTriggerEventForAddOnCancellation = baseChangeEvent;
@@ -1051,7 +1053,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     }
 
-    private SubscriptionBase createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionBaseEvent> events, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+    private DefaultSubscriptionBase createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionBaseEvent> events, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
         final DefaultSubscriptionBase result = new DefaultSubscriptionBase(new SubscriptionBuilder(((DefaultSubscriptionBase) shellSubscription)), null, clock);
 
         if (!events.isEmpty()) {
@@ -1060,9 +1062,9 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         return result;
     }
 
-    private SubscriptionBase getBaseSubscription(final UUID bundleId, final boolean rebuildSubscription, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
-        final List<SubscriptionBase> subscriptions = getSubscriptionFromBundleId(bundleId, context);
-        for (final SubscriptionBase cur : subscriptions) {
+    private DefaultSubscriptionBase getBaseSubscription(final UUID bundleId, final boolean rebuildSubscription, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
+        final List<DefaultSubscriptionBase> subscriptions = getSubscriptionFromBundleId(bundleId, context);
+        for (final DefaultSubscriptionBase cur : subscriptions) {
             if (cur.getCategory() == ProductCategory.BASE) {
                 return rebuildSubscription ? buildSubscription(cur, catalog, context) : cur;
             }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionModelDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionModelDao.java
index e0761b9..d7adf33 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionModelDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionModelDao.java
@@ -105,7 +105,7 @@ public class SubscriptionModelDao extends EntityModelDaoBase implements EntityMo
         this.migrated = migrated;
     }
 
-    public static SubscriptionBase toSubscription(final SubscriptionModelDao src, final String externalKey) {
+    public static DefaultSubscriptionBase toSubscription(final SubscriptionModelDao src, final String externalKey) {
         if (src == null) {
             return null;
         }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
index 242676b..64fdc9a 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
@@ -64,9 +64,9 @@ public interface SubscriptionDao extends EntityDao<SubscriptionBundleModelDao, S
     // SubscriptionBase retrieval
     public SubscriptionBase getBaseSubscription(UUID bundleId, final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
 
-    public List<SubscriptionBase> getSubscriptions(UUID bundleId, List<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
+    public List<DefaultSubscriptionBase> getSubscriptions(UUID bundleId, List<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
 
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
+    public Map<UUID, List<DefaultSubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
 
     // Update
     public void updateChargedThroughDate(DefaultSubscriptionBase subscription, InternalCallContext context);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestDefaultSubscriptionBase.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestDefaultSubscriptionBase.java
index 9dff853..fab5df1 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestDefaultSubscriptionBase.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestDefaultSubscriptionBase.java
@@ -41,7 +41,8 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testCancelSOT() throws Exception {
-        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder());
+        final DateTime startDate = new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC);
+        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder().setAlignStartDate(startDate));
 
         final UUID subscriptionId = UUID.randomUUID();
         final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
@@ -52,9 +53,9 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
                                                                 .setFromDisk(true)
                                                                 .setUuid(UUID.randomUUID())
                                                                 .setSubscriptionId(subscriptionId)
-                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
-                                                                .setUpdatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
-                                                                .setEffectiveDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setCreatedDate(startDate)
+                                                                .setUpdatedDate(startDate)
+                                                                .setEffectiveDate(startDate)
                                                                 .setTotalOrdering(3)
                                                                 .setActive(true)));
         inputEvents.add(new ApiEventCancel(new ApiEventBuilder().setApiEventType(ApiEventType.CANCEL)
@@ -64,9 +65,9 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
                                                                 .setFromDisk(false)
                                                                 .setUuid(UUID.randomUUID())
                                                                 .setSubscriptionId(subscriptionId)
-                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setCreatedDate(startDate)
                                                                 .setUpdatedDate(null)
-                                                                .setEffectiveDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setEffectiveDate(startDate)
                                                                 .setTotalOrdering(0) // In-memory event
                                                                 .setActive(true)));
         subscriptionBase.rebuildTransitions(inputEvents, catalog);
@@ -74,15 +75,16 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(subscriptionBase.getAllTransitions().size(), 2);
         Assert.assertNull(subscriptionBase.getAllTransitions().get(0).getPreviousState());
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getNextState(), EntitlementState.ACTIVE);
-        Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getEffectiveTransitionTime(), new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC));
+        Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getEffectiveTransitionTime(), startDate);
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getPreviousState(), EntitlementState.ACTIVE);
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getNextState(), EntitlementState.CANCELLED);
-        Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getEffectiveTransitionTime(), new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC));
+        Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getEffectiveTransitionTime(), startDate);
     }
 
     @Test(groups = "fast", description = "https://github.com/killbill/killbill/issues/897")
     public void testFutureCancelBeforePhase() throws Exception {
-        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder());
+        final DateTime startDate = new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC);
+        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder().setAlignStartDate(startDate));
 
         final UUID subscriptionId = UUID.randomUUID();
         final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
@@ -93,16 +95,16 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
                                                                 .setFromDisk(true)
                                                                 .setUuid(UUID.randomUUID())
                                                                 .setSubscriptionId(subscriptionId)
-                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
-                                                                .setUpdatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
-                                                                .setEffectiveDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setCreatedDate(startDate)
+                                                                .setUpdatedDate(startDate)
+                                                                .setEffectiveDate(startDate)
                                                                 .setTotalOrdering(3)
                                                                 .setActive(true)));
         inputEvents.add(new PhaseEventData(new PhaseEventBuilder().setPhaseName("laser-scope-monthly-evergreen")
                                                                   .setUuid(UUID.randomUUID())
                                                                   .setSubscriptionId(subscriptionId)
-                                                                  .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
-                                                                  .setUpdatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                  .setCreatedDate(startDate)
+                                                                  .setUpdatedDate(startDate)
                                                                   .setEffectiveDate(new DateTime(2012, 6, 1, 0, 0, DateTimeZone.UTC))
                                                                   .setTotalOrdering(4)
                                                                   .setActive(true)));
@@ -113,7 +115,7 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
                                                                 .setFromDisk(false)
                                                                 .setUuid(UUID.randomUUID())
                                                                 .setSubscriptionId(subscriptionId)
-                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setCreatedDate(startDate)
                                                                 .setUpdatedDate(null)
                                                                 .setEffectiveDate(new DateTime(2012, 6, 1, 0, 0, DateTimeZone.UTC))
                                                                 .setTotalOrdering(0) // In-memory event
@@ -123,7 +125,7 @@ public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(subscriptionBase.getAllTransitions().size(), 2);
         Assert.assertNull(subscriptionBase.getAllTransitions().get(0).getPreviousState());
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getNextState(), EntitlementState.ACTIVE);
-        Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getEffectiveTransitionTime(), new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC));
+        Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getEffectiveTransitionTime(), startDate);
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getPreviousState(), EntitlementState.ACTIVE);
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getNextState(), EntitlementState.CANCELLED);
         Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getEffectiveTransitionTime(), new DateTime(2012, 6, 1, 0, 0, DateTimeZone.UTC));
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
index 4503630..4999f00 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project 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:
  *
@@ -398,10 +400,11 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanSpecifier planSpecifier = new PlanSpecifier(aoProduct,
                                                               aoTerm,
                                                               aoPriceList);
-        final PlanAlignmentCreate alignement = catalog.planCreateAlignment(planSpecifier, clock.getUTCNow());
-        assertEquals(alignement, PlanAlignmentCreate.START_OF_BUNDLE);
+        final DateTime utcNow = clock.getUTCNow();
+        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, utcNow, utcNow);
+        assertEquals(alignment, PlanAlignmentCreate.START_OF_BUNDLE);
 
-        testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignement);
+        testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignment);
     }
 
     @Test(groups = "slow")
@@ -414,10 +417,11 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanSpecifier planSpecifier = new PlanSpecifier(aoProduct,
                                                               aoTerm,
                                                               aoPriceList);
-        final PlanAlignmentCreate alignement = catalog.planCreateAlignment(planSpecifier, clock.getUTCNow());
-        assertEquals(alignement, PlanAlignmentCreate.START_OF_SUBSCRIPTION);
+        final DateTime utcNow = clock.getUTCNow();
+        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, utcNow, utcNow);
+        assertEquals(alignment, PlanAlignmentCreate.START_OF_SUBSCRIPTION);
 
-        testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignement);
+        testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignment);
     }
 
     private void testAddonCreateInternal(final String aoProduct, final BillingPeriod aoTerm, final String aoPriceList, final PlanAlignmentCreate expAlignement) throws SubscriptionBaseApiException {
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index 8b5a74e..36b05f0 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -78,7 +78,7 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
     protected static final Logger log = LoggerFactory.getLogger(SubscriptionDao.class);
 
     private final List<SubscriptionBaseBundle> bundles;
-    private final List<SubscriptionBase> subscriptions;
+    private final List<DefaultSubscriptionBase> subscriptions;
     private final TreeSet<SubscriptionBaseEvent> events;
 
     private final MockNonEntityDao mockNonEntityDao;
@@ -100,7 +100,7 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
         this.notificationQueueService = notificationQueueService;
         this.eventBus = eventBus;
         this.bundles = new ArrayList<SubscriptionBaseBundle>();
-        this.subscriptions = new ArrayList<SubscriptionBase>();
+        this.subscriptions = new ArrayList<DefaultSubscriptionBase>();
         this.events = new TreeSet<SubscriptionBaseEvent>();
     }
 
@@ -216,7 +216,7 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
                     for (final SubscriptionBaseEvent cur : initialEvents) {
                         recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new SubscriptionNotificationKey(cur.getId()), context);
                     }
-                    final SubscriptionBase updatedSubscription = buildSubscription((DefaultSubscriptionBase) subscriptionBase, context);
+                    final DefaultSubscriptionBase updatedSubscription = buildSubscription((DefaultSubscriptionBase) subscriptionBase, context);
                     this.subscriptions.add(updatedSubscription);
                     mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
 
@@ -229,24 +229,24 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
     }
 
     @Override
-    public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents,  final Catalog catalog, final InternalTenantContext context) {
-        final List<SubscriptionBase> results = new ArrayList<SubscriptionBase>();
-        for (final SubscriptionBase cur : subscriptions) {
+    public List<DefaultSubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final Catalog catalog, final InternalTenantContext context) {
+        final List<DefaultSubscriptionBase> results = new ArrayList<DefaultSubscriptionBase>();
+        for (final DefaultSubscriptionBase cur : subscriptions) {
             if (cur.getBundleId().equals(bundleId)) {
-                results.add(buildSubscription((DefaultSubscriptionBase) cur, context));
+                results.add(buildSubscription(cur, context));
             }
         }
         return results;
     }
 
     @Override
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, final InternalTenantContext context) {
-        final Map<UUID, List<SubscriptionBase>> results = new HashMap<UUID, List<SubscriptionBase>>();
-        for (final SubscriptionBase cur : subscriptions) {
+    public Map<UUID, List<DefaultSubscriptionBase>> getSubscriptionsForAccount(final Catalog catalog, final InternalTenantContext context) {
+        final Map<UUID, List<DefaultSubscriptionBase>> results = new HashMap<UUID, List<DefaultSubscriptionBase>>();
+        for (final DefaultSubscriptionBase cur : subscriptions) {
             if (results.get(cur.getBundleId()) == null) {
-                results.put(cur.getBundleId(), new LinkedList<SubscriptionBase>());
+                results.put(cur.getBundleId(), new LinkedList<DefaultSubscriptionBase>());
             }
-            results.get(cur.getBundleId()).add(buildSubscription((DefaultSubscriptionBase) cur, context));
+            results.get(cur.getBundleId()).add(buildSubscription(cur, context));
         }
         return results;
     }
@@ -297,9 +297,9 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
         notifyBusOfEffectiveImmediateChange(subscription, readyPhaseEvent, 0, context);
     }
 
-    private SubscriptionBase buildSubscription(final DefaultSubscriptionBase in, final InternalTenantContext context) {
+    private DefaultSubscriptionBase buildSubscription(final DefaultSubscriptionBase in, final InternalTenantContext context) {
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(new SubscriptionBuilder(in), null, clock);
-        if (events.size() > 0) {
+        if (!events.isEmpty()) {
             try {
                 subscription.rebuildTransitions(getEventsForSubscription(in.getId(), context), catalogService.getFullCatalog(true, true, context));
             } catch (final CatalogApiException e) {
@@ -307,13 +307,12 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
             }
         }
         return subscription;
-
     }
 
     @Override
     public void updateChargedThroughDate(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
         boolean found = false;
-        final Iterator<SubscriptionBase> it = subscriptions.iterator();
+        final Iterator<DefaultSubscriptionBase> it = subscriptions.iterator();
         while (it.hasNext()) {
             final SubscriptionBase cur = it.next();
             if (cur.getId().equals(subscription.getId())) {
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java
index c3bb42a..7ca3747 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java
@@ -77,6 +77,9 @@ public class TestSubscriptionDao extends SubscriptionTestSuiteWithEmbeddedDB {
     @Override // to ignore events
     @AfterMethod(groups = "slow")
     public void afterMethod() throws Exception {
+        if (hasFailed()) {
+            return;
+        }
         subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
     }
 

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

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 3eb796b..4696115 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

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

diff --git a/usage/pom.xml b/usage/pom.xml
index 004bc90..f8bf1e1 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

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

diff --git a/util/pom.xml b/util/pom.xml
index 9c8d674..faa7cc2 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.15-SNAPSHOT</version>
+        <version>0.19.16-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
index 05bea16..61db3ab 100644
--- a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
+++ b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
@@ -18,6 +18,7 @@ package org.killbill.billing.util.export.dao;
 
 import java.io.IOException;
 import java.sql.Blob;
+import java.sql.Clob;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -169,11 +170,15 @@ public class DatabaseExportDao {
 
                         for (final String k : row.keySet()) {
                             final Object value = row.get(k);
-                            // For h2, transform a JdbcBlob into a byte[]
+                            // For h2, transform a JdbcBlob and a JdbcClob into a byte[]
                             // See also LowerToCamelBeanMapper
                             if (value instanceof Blob) {
                                 final Blob blob = (Blob) value;
                                 row.put(k, blob.getBytes(0, (int) blob.length()));
+                            } else if (value instanceof Clob) {
+                                // TODO Update LowerToCamelBeanMapper?
+                                final Clob clob = (Clob) value;
+                                row.put(k, clob.getSubString(1, (int) clob.length()));
                             }
                         }
 
diff --git a/util/src/test/java/org/killbill/billing/api/TestApiListener.java b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
index 83cb4c2..b431636 100644
--- a/util/src/test/java/org/killbill/billing/api/TestApiListener.java
+++ b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
@@ -324,8 +324,12 @@ public class TestApiListener {
                 } catch (final Exception ignore) {
                     // Rerun one more time to provide details
                     final long pending = idbi.withHandle(new PendingBusOrNotificationCallback(clock));
-                    log.error("isCompleted : Received all events but found remaining unprocessed bus events/notifications =  {}", pending);
-                    return false;
+                    if (pending != 0) {
+                        log.error("isCompleted : Received all events but found remaining unprocessed bus events/notifications = {}", pending);
+                        return false;
+                    } else {
+                        return completed;
+                    }
                 }
             } while (waitTimeMs > 0 && !completed);
         }