killbill-memoizeit

Changes

jaxrs/pom.xml 8(+8 -0)

pom.xml 2(+1 -1)

Details

diff --git a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java
index 4bdf0c6..b7f27de 100644
--- a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2016-2017 Groupon, Inc
- * Copyright 2016-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
@@ -19,6 +19,8 @@ package org.killbill.billing.account.api.svcs;
 
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
@@ -44,6 +46,8 @@ import org.skife.jdbi.v2.IDBI;
 
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultImmutableAccountInternalApi implements ImmutableAccountInternalApi {
 
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
@@ -53,11 +57,12 @@ public class DefaultImmutableAccountInternalApi implements ImmutableAccountInter
 
     @Inject
     public DefaultImmutableAccountInternalApi(final IDBI dbi,
+                                              @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi,
                                               final Clock clock,
                                               final NonEntityDao nonEntityDao,
                                               final CacheControllerDispatcher cacheControllerDispatcher) {
         // This API will directly issue queries instead of relying on the DAO (introduced to avoid Guice circular dependencies with InternalCallContextFactory)
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, null);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, null);
         this.nonEntityDao = nonEntityDao;
         this.accountCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
         this.recordIdCacheController = cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID);
@@ -89,7 +94,7 @@ public class DefaultImmutableAccountInternalApi implements ImmutableAccountInter
     }
 
     private Account getAccountByRecordIdInternal(final Long recordId, final InternalTenantContext context) {
-        final AccountModelDao accountModelDao = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
+        final AccountModelDao accountModelDao = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
 
             @Override
             public AccountModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
diff --git a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
index 919ccf3..a2a5ea3 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.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
@@ -22,6 +22,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.killbill.billing.BillingExceptionBase;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
@@ -57,10 +59,11 @@ import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, AccountApiException> implements AccountDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultAccountDao.class);
@@ -71,10 +74,10 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
     private final Clock clock;
 
     @Inject
-    public DefaultAccountDao(final IDBI dbi, final PersistentBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+    public DefaultAccountDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final PersistentBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                              final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), AccountSqlDao.class);
-        this.accountImmutableCacheController  = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), AccountSqlDao.class);
+        this.accountImmutableCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
         this.eventBus = eventBus;
         this.internalCallContextFactory = internalCallContextFactory;
         this.clock = clock;
@@ -90,7 +93,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
             entity.setReferenceTime(context.getCreatedDate());
         }
 
-        final AccountModelDao refreshedEntity = transactionalSqlDao.execute(getCreateEntitySqlDaoTransactionWrapper(entity, context));
+        final AccountModelDao refreshedEntity = transactionalSqlDao.execute(false, getCreateEntitySqlDaoTransactionWrapper(entity, context));
         // Populate the caches only after the transaction has been committed, in case of rollbacks
         transactionalSqlDao.populateCaches(refreshedEntity);
         // Eagerly populate the account-immutable cache as well
@@ -127,7 +130,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public AccountModelDao getAccountByKey(final String key, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
             @Override
             public AccountModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getAccountByKey(key, context);
@@ -141,7 +144,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
         if (userIsFeelingLucky) {
             // The use-case we can optimize is when the user is looking for an exact match (e.g. he knows the full email). In that case, we can speed up the queries
             // by doing exact searches only.
-            final AccountModelDao accountModelDao = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
+            final AccountModelDao accountModelDao = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
                 @Override
                 public AccountModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                     return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).luckySearch(searchKey, context);
@@ -179,7 +182,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
             throw new AccountApiException(ErrorCode.ACCOUNT_CANNOT_MAP_NULL_KEY, "");
         }
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<UUID>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<UUID>() {
             @Override
             public UUID inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getIdFromKey(externalKey, context);
@@ -189,7 +192,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public void update(final AccountModelDao specifiedAccount, final InternalCallContext context) throws AccountApiException {
-        transactionalSqlDao.execute(AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws EventBusException, AccountApiException {
                 final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
@@ -222,7 +225,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
-        transactionalSqlDao.execute(AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws EntityPersistenceException, EventBusException {
                 final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
@@ -259,7 +262,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) throws AccountApiException {
-        transactionalSqlDao.execute(AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, AccountApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final AccountEmailSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class);
@@ -276,7 +279,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public void removeEmail(final AccountEmailModelDao email, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class).markEmailAsDeleted(email, context);
@@ -287,7 +290,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public List<AccountEmailModelDao> getEmailsByAccountId(final UUID accountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AccountEmailModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<AccountEmailModelDao>>() {
             @Override
             public List<AccountEmailModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class).getEmailByAccountId(accountId, context);
@@ -297,7 +300,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public Integer getAccountBCD(final UUID accountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Integer>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Integer>() {
             @Override
             public Integer inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getBCD(accountId.toString(), context);
@@ -307,7 +310,7 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
 
     @Override
     public List<AccountModelDao> getAccountsByParentId(final UUID parentAccountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AccountModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<AccountModelDao>>() {
             @Override
             public List<AccountModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getAccountsByParentId(parentAccountId, context);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
index a0c5599..357cef0 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
@@ -92,16 +92,22 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
             assertEquals(e.getCode(), ErrorCode.CAT_PLAN_NOT_FOUND.getCode());
         }
 
+
+        final DefaultEntitlement bpEntitlement2 =
+                createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey2", "Bazooka",
+                                                           ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        assertNotNull(bpEntitlement2);
+
+
         // Move out a month and verify 'Pistol' plan continue working as expected.
         busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
         clock.addMonths(1);
         assertListenerStatus();
 
+
         final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
-        assertEquals(invoices.size(), 3);
-        for (final Invoice invoice : invoices) {
-            assertEquals(invoice.getInvoiceItems().get(0).getPlanName(), "pistol-monthly");
-        }
+        assertEquals(invoices.size(), 4);
+
     }
 
     // Flaky, see https://github.com/killbill/killbill/issues/860
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index fb33ba6..50b114a 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.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
@@ -28,7 +28,6 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.Interval;
 import org.joda.time.LocalDate;
-import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.api.TestApiListener.NextEvent;
@@ -45,6 +44,7 @@ import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.SubscriptionBundle;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
+import org.killbill.billing.invoice.api.DryRunArguments;
 import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
@@ -60,13 +60,132 @@ import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
 
+import static org.killbill.billing.ErrorCode.INVOICE_NOTHING_TO_DO;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 public class TestIntegration extends TestIntegrationBase {
 
+    @Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/897")
+    public void testFutureCancelBPWithAOBeforePhase() throws Exception {
+        // We take april as it has 30 days (easier to play with BCD)
+        // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+        clock.setDay(new LocalDate(2012, 4, 1));
+
+        final AccountData accountData = getAccountData(1);
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+        accountChecker.checkAccount(account.getId(), accountData, callContext);
+
+        final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+
+        //
+        // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE, NextEvent.BLOCK NextEvent.INVOICE
+        //
+        final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+        // Check bundle after BP got created otherwise we get an error from auditApi.
+        subscriptionChecker.checkSubscriptionCreated(bpSubscription.getId(), internalCallContext);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+        invoiceChecker.checkInvoice(account.getId(), 1, callContext, expectedInvoices);
+        expectedInvoices.clear();
+
+        addMonthsAndCheckForCompletion(1, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+        final Invoice invoice2 = invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+        paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 5, 1), new BigDecimal("249.95"), TransactionStatus.SUCCESS, invoice2.getId(), Currency.USD));
+        expectedInvoices.clear();
+
+        //
+        // ADD ADD_ON (Laser-Scope has a START_OF_SUBSCRIPTION create alignment)
+        //
+        addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("999.95")));
+        final Invoice invoice3 = invoiceChecker.checkInvoice(account.getId(), 3, callContext, expectedInvoices);
+        paymentChecker.checkPayment(account.getId(), 2, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 5, 1), new BigDecimal("999.95"), TransactionStatus.SUCCESS, invoice3.getId(), Currency.USD));
+        expectedInvoices.clear();
+
+        //
+        // CANCEL BP
+        //
+        cancelEntitlementAndCheckForCompletion(bpSubscription, EntitlementActionPolicy.END_OF_TERM, BillingActionPolicy.END_OF_TERM);
+
+        // Verify we can trigger a dry-run invoice while the cancellation is pending
+        final DryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
+                                                               bpSubscription.getBundleId(), null, null);
+        try {
+            invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(2012, 6, 1), dryRun, callContext);
+            fail();
+        } catch (final InvoiceApiException e) {
+            assertEquals(e.getCode(), INVOICE_NOTHING_TO_DO.getCode());
+        }
+
+        addMonthsAndCheckForCompletion(1, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
+
+        checkNoMoreInvoiceToGenerate(account);
+    }
+
+    @Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/897")
+    public void testFutureCancelBPWithAOAfterPhase() throws Exception {
+        // We take april as it has 30 days (easier to play with BCD)
+        // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+        clock.setDay(new LocalDate(2012, 4, 1));
+
+        final AccountData accountData = getAccountData(1);
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+        accountChecker.checkAccount(account.getId(), accountData, callContext);
+
+        final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+
+        //
+        // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE, NextEvent.BLOCK NextEvent.INVOICE
+        //
+        final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+        // Check bundle after BP got created otherwise we get an error from auditApi.
+        subscriptionChecker.checkSubscriptionCreated(bpSubscription.getId(), internalCallContext);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+        invoiceChecker.checkInvoice(account.getId(), 1, callContext, expectedInvoices);
+        expectedInvoices.clear();
+
+        //
+        // ADD ADD_ON
+        //
+        addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
+        final Invoice invoice2 = invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+        paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), TransactionStatus.SUCCESS, invoice2.getId(), Currency.USD));
+        expectedInvoices.clear();
+
+        // Go past the PHASE events
+        addMonthsAndCheckForCompletion(1, NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("999.95")));
+        final Invoice invoice3 = invoiceChecker.checkInvoice(account.getId(), 3, callContext, expectedInvoices);
+        expectedInvoices.clear();
+        paymentChecker.checkPayment(account.getId(), 2, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 5, 1), new BigDecimal("1249.9"), TransactionStatus.SUCCESS, invoice3.getId(), Currency.USD));
+        expectedInvoices.clear();
+
+        //
+        // CANCEL BP EOT
+        //
+        cancelEntitlementAndCheckForCompletion(bpSubscription, EntitlementActionPolicy.END_OF_TERM, BillingActionPolicy.END_OF_TERM);
+
+        // Verify we can trigger a dry-run invoice while the cancellation is pending
+        final DryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
+                                                               bpSubscription.getBundleId(), null, null);
+        try {
+            invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(2012, 6, 1), dryRun, callContext);
+            fail();
+        } catch (final InvoiceApiException e) {
+            assertEquals(e.getCode(), INVOICE_NOTHING_TO_DO.getCode());
+        }
+
+        addMonthsAndCheckForCompletion(1, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
+
+        checkNoMoreInvoiceToGenerate(account);
+    }
+
     @Test(groups = "slow")
     public void testCancelBPWithAOTheSameDay() throws Exception {
         // We take april as it has 30 days (easier to play with BCD)
@@ -296,7 +415,7 @@ public class TestIntegration extends TestIntegrationBase {
            invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
             Assert.fail("Call should return no invoices");
         } catch (final InvoiceApiException e) {
-            assertEquals(e.getCode(), ErrorCode.INVOICE_NOTHING_TO_DO.getCode());
+            assertEquals(e.getCode(), INVOICE_NOTHING_TO_DO.getCode());
         }
 
         baseEntitlement = changeEntitlementAndCheckForCompletion(baseEntitlement, "Pistol", BillingPeriod.MONTHLY, null);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index c3b2036..dc48f98 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.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
@@ -62,6 +62,7 @@ import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.entitlement.api.BlockingStateType;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
 import org.killbill.billing.entitlement.api.Entitlement;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.entitlement.api.EntitlementApi;
 import org.killbill.billing.entitlement.api.EntitlementApiException;
 import org.killbill.billing.entitlement.api.SubscriptionApi;
@@ -125,9 +126,7 @@ import org.skife.config.TimeSpan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
-import org.testng.IHookCallBack;
 import org.testng.IHookable;
-import org.testng.ITestResult;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
@@ -762,6 +761,26 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
         }, events);
     }
 
+    protected DefaultEntitlement cancelEntitlementAndCheckForCompletion(final Entitlement entitlement,
+                                                                        final EntitlementActionPolicy entitlementActionPolicy,
+                                                                        final BillingActionPolicy billingActionPolicy,
+                                                                        final NextEvent... events) {
+        return (DefaultEntitlement) doCallAndCheckForCompletion(new Function<Void, Entitlement>() {
+            @Override
+            public Entitlement apply(@Nullable final Void dontcare) {
+                try {
+                    // Need to fetch again to get latest CTD updated from the system
+                    Entitlement refreshedEntitlement = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+                    refreshedEntitlement = refreshedEntitlement.cancelEntitlementWithPolicyOverrideBillingPolicy(entitlementActionPolicy, billingActionPolicy, ImmutableList.<PluginProperty>of(), callContext);
+                    return refreshedEntitlement;
+                } catch (final EntitlementApiException e) {
+                    fail(e.getMessage());
+                    return null;
+                }
+            }
+        }, events);
+    }
+
     protected void fullyAdjustInvoiceAndCheckForCompletion(final Account account, final Invoice invoice, final NextEvent... events) {
         doCallAndCheckForCompletion(new Function<Void, Void>() {
             @Override
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
index 0357f98..049f602 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
@@ -409,6 +409,8 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
         // Account in PDT
         final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
                                                                 .timeZone(timeZone)
+                                                                // Fixed reference time, regardless of current DST
+                                                                .referenceTime(clock.getUTCNow())
                                                                 .build();
 
         final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
index 5a977b6..9cd2a82 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
@@ -91,6 +91,11 @@
                 <alignment>START_OF_BUNDLE</alignment>
             </createAlignmentCase>
         </createAlignment>
+        <billingAlignment>
+            <billingAlignmentCase>
+                <alignment>BUNDLE</alignment>
+            </billingAlignmentCase>
+        </billingAlignment>
         <priceList>
             <priceListCase>
                 <fromPriceList>SpecialDiscount</fromPriceList>
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
index c575b09..d9fe488 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
@@ -48,6 +48,9 @@
                 </limit>
             </limits>
         </product>
+        <product name="Bazooka">
+            <category>BASE</category>
+        </product>
         <product name="Laser-Scope">
             <category>ADD_ON</category>
         </product>
@@ -91,6 +94,11 @@
                 <alignment>START_OF_BUNDLE</alignment>
             </createAlignmentCase>
         </createAlignment>
+        <billingAlignment>
+            <billingAlignmentCase>
+                <alignment>BUNDLE</alignment>
+            </billingAlignmentCase>
+        </billingAlignment>
         <priceList>
             <priceListCase>
                 <fromPriceList>SpecialDiscount</fromPriceList>
@@ -297,6 +305,35 @@
                 </recurring>
             </finalPhase>
         </plan>
+        <plan name="bazooka-monthly">
+            <product>Bazooka</product>
+            <initialPhases>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                    <number>-1</number>
+                </duration>
+                <recurring>
+                    <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>500.00</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>300.00</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>300.00</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
+
     </plans>
     <priceLists>
         <defaultPriceList name="DEFAULT">
@@ -305,6 +342,7 @@
                 <plan>shotgun-annual</plan>
                 <plan>laser-scope-monthly</plan>
                 <plan>extra-ammo-monthly</plan>
+                <plan>bazooka-monthly</plan>
             </plans>
         </defaultPriceList>
         <childPriceList name="SpecialDiscount">
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
index 63acb70..8c7a4ee 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
@@ -89,6 +89,11 @@
                 <alignment>START_OF_BUNDLE</alignment>
             </createAlignmentCase>
         </createAlignment>
+        <billingAlignment>
+            <billingAlignmentCase>
+                <alignment>BUNDLE</alignment>
+            </billingAlignmentCase>
+        </billingAlignment>
     </rules>
 
     <plans>
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java
index 29c193c..70f7762 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.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
@@ -29,6 +29,7 @@ import java.util.Map;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
+import javax.inject.Named;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
@@ -73,6 +74,8 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao, BlockingState, EntitlementApiException> implements BlockingStateDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultBlockingStateDao.class);
@@ -112,9 +115,9 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     private final StatelessBlockingChecker statelessBlockingChecker = new StatelessBlockingChecker();
 
-    public DefaultBlockingStateDao(final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
+    public DefaultBlockingStateDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
                                    final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BlockingStateSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BlockingStateSqlDao.class);
         this.clock = clock;
         this.notificationQueueService = notificationQueueService;
         this.eventBus = eventBus;
@@ -129,7 +132,7 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     @Override
     public BlockingState getBlockingStateForService(final UUID blockableId, final BlockingStateType blockingStateType, final String serviceName, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<BlockingState>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<BlockingState>() {
             @Override
             public BlockingState inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 // Upper bound time limit is now
@@ -142,7 +145,7 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     @Override
     public List<BlockingState> getBlockingState(final UUID blockableId, final BlockingStateType blockingStateType, final DateTime upToDate, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
             @Override
             public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
@@ -166,7 +169,7 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     @Override
     public List<BlockingState> getBlockingAllForAccountRecordId(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
             @Override
             public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
@@ -183,7 +186,7 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     @Override
     public void setBlockingStatesAndPostBlockingTransitionEvent(final Map<BlockingState, Optional<UUID>> states, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
@@ -359,7 +362,7 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
 
     @Override
     public void unactiveBlockingState(final UUID id, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
index 35c718a..eb415a0 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.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
@@ -47,9 +47,9 @@ import com.google.common.collect.ImmutableList;
 public class OptimizedProxyBlockingStateDao extends ProxyBlockingStateDao {
 
     public OptimizedProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
-                                          final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
+                                          final IDBI dbi, final IDBI roDbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
                                           final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(eventsStreamBuilder, subscriptionBaseInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        super(eventsStreamBuilder, subscriptionBaseInternalApi, dbi, roDbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     /**
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
index ea237a3..ad5c151 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.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
@@ -27,6 +27,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.joda.time.DateTime;
@@ -60,6 +61,8 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Ordering;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 @Singleton
 public class ProxyBlockingStateDao implements BlockingStateDao {
 
@@ -171,12 +174,12 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
 
     @Inject
     public ProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
-                                 final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
+                                 final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
                                  final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
         this.eventsStreamBuilder = eventsStreamBuilder;
         this.subscriptionInternalApi = subscriptionBaseInternalApi;
         this.clock = clock;
-        this.delegate = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        this.delegate = new DefaultBlockingStateDao(dbi, roDbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     @Override
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 b2b436a..ef40ca5 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
@@ -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
@@ -28,6 +28,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.killbill.billing.ObjectType;
@@ -71,6 +72,8 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 @Singleton
 public class EventsStreamBuilder {
 
@@ -84,7 +87,7 @@ public class EventsStreamBuilder {
 
     @Inject
     public EventsStreamBuilder(final AccountInternalApi accountInternalApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
-                               final BlockingChecker checker, final IDBI dbi, final Clock clock,
+                               final BlockingChecker checker, final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock,
                                final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
                                final CacheControllerDispatcher cacheControllerDispatcher,
                                final NonEntityDao nonEntityDao,
@@ -94,8 +97,8 @@ public class EventsStreamBuilder {
         this.checker = checker;
         this.clock = clock;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.defaultBlockingStateDao = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
-        this.blockingStateDao = new OptimizedProxyBlockingStateDao(this, subscriptionInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        this.defaultBlockingStateDao = new DefaultBlockingStateDao(dbi, roDbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        this.blockingStateDao = new OptimizedProxyBlockingStateDao(this, subscriptionInternalApi, dbi, roDbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     public EventsStream refresh(final EventsStream eventsStream, final TenantContext tenantContext) throws EntitlementApiException {
@@ -335,7 +338,6 @@ public class EventsStreamBuilder {
                                              final Map<UUID, Integer> bcdCache,
                                              final InternalTenantContext internalTenantContext) throws EntitlementApiException {
 
-
         try {
             int accountBCD = accountInternalApi.getBCD(account.getId(), internalTenantContext);
             int defaultAlignmentDay = subscriptionInternalApi.getDefaultBillCycleDayLocal(bcdCache, subscription, baseSubscription, createPlanPhaseSpecifier(subscription), accountBCD, clock.getUTCNow(), internalTenantContext);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index 8720a38..51d646b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.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
@@ -30,6 +30,7 @@ import java.util.Set;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
+import javax.inject.Named;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
@@ -86,12 +87,13 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Ordering;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, InvoiceApiException> implements InvoiceDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultInvoiceDao.class);
@@ -126,6 +128,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     @Inject
     public DefaultInvoiceDao(final TagInternalApi tagInternalApi,
                              final IDBI dbi,
+                             @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi,
                              final NextBillingDatePoster nextBillingDatePoster,
                              final PersistentBus eventBus,
                              final Clock clock,
@@ -136,7 +139,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                              final CBADao cbaDao,
                              final ParentInvoiceCommitmentPoster parentInvoiceCommitmentPoster,
                              final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), InvoiceSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), InvoiceSqlDao.class);
         this.tagInternalApi = tagInternalApi;
         this.nextBillingDatePoster = nextBillingDatePoster;
         this.eventBus = eventBus;
@@ -159,7 +162,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public List<InvoiceModelDao> getInvoicesByAccount(final Boolean includeVoidedInvoices, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -183,7 +186,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public List<InvoiceModelDao> getAllInvoicesByAccount(final Boolean includeVoidedInvoices, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return invoiceDaoHelper.getAllInvoicesByAccountFromTransaction(includeVoidedInvoices, invoicesTags, entitySqlDaoWrapperFactory, context);
@@ -195,7 +198,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public List<InvoiceModelDao> getInvoicesByAccount(final Boolean includeVoidedInvoices, final LocalDate fromDate, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -222,7 +225,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public InvoiceModelDao getById(final UUID invoiceId, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
             @Override
             public InvoiceModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -245,7 +248,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
             @Override
             public InvoiceModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -269,7 +272,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public void setFutureAccountNotificationsForEmptyInvoice(final UUID accountId, final FutureAccountNotifications callbackDateTimePerSubscriptions,
                                                              final InternalCallContext context) {
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, accountId, callbackDateTimePerSubscriptions, context);
@@ -319,7 +322,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
         final Map<UUID, InvoiceModelDao> invoiceByInvoiceId = new HashMap<UUID, InvoiceModelDao>();
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceItemModelDao>>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<List<InvoiceItemModelDao>>() {
             @Override
             public List<InvoiceItemModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -359,7 +362,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                     }
 
                     final boolean wasInvoiceCreatedOrCommitted = createdInvoiceIds.contains(invoiceModelDao.getId()) ||
-                                                       committedReusedInvoiceId.contains(invoiceModelDao.getId());
+                                                                 committedReusedInvoiceId.contains(invoiceModelDao.getId());
                     if (InvoiceStatus.COMMITTED.equals(invoiceModelDao.getStatus())) {
 
                         if (wasInvoiceCreatedOrCommitted) {
@@ -401,7 +404,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public List<InvoiceModelDao> getInvoicesBySubscription(final UUID subscriptionId, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -451,7 +454,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public BigDecimal getAccountBalance(final UUID accountId, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<BigDecimal>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<BigDecimal>() {
             @Override
             public BigDecimal inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 BigDecimal cba = BigDecimal.ZERO;
@@ -472,7 +475,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                              cur.getParentInvoice().getStatus() == InvoiceStatus.VOID ||
                              InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(cur.getParentInvoice()).compareTo(BigDecimal.ZERO) == 0);
 
-
                     // invoices that are WRITTEN_OFF or paid children invoices are excluded from balance computation but the cba summation needs to be included
                     accountBalance = cur.isWrittenOff() || hasZeroParentBalance ? BigDecimal.ZERO : accountBalance.add(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(cur));
                     cba = cba.add(InvoiceModelDaoHelper.getCBAAmount(cur));
@@ -484,7 +486,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public BigDecimal getAccountCBA(final UUID accountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<BigDecimal>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<BigDecimal>() {
             @Override
             public BigDecimal inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return cbaDao.getAccountCBAFromTransaction(entitySqlDaoWrapperFactory, context);
@@ -496,7 +498,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public List<InvoiceModelDao> getUnpaidInvoicesByAccountId(final UUID accountId, @Nullable final LocalDate upToDate, final InternalTenantContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return invoiceDaoHelper.getUnpaidInvoicesByAccountFromTransaction(accountId, invoicesTags, entitySqlDaoWrapperFactory, upToDate, context);
@@ -506,7 +508,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public UUID getInvoiceIdByPaymentId(final UUID paymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<UUID>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<UUID>() {
             @Override
             public UUID inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class).getInvoiceIdByPaymentId(paymentId.toString(), context);
@@ -516,7 +518,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoicePaymentModelDao> getInvoicePaymentsByPaymentId(final UUID paymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
             @Override
             public List<InvoicePaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getInvoicePayments(paymentId.toString(), context);
@@ -526,7 +528,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoicePaymentModelDao> getInvoicePaymentsByAccount(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
             @Override
             public List<InvoicePaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getByAccountRecordId(context);
@@ -539,14 +541,13 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                                final Map<UUID, BigDecimal> invoiceItemIdsWithNullAmounts, final String transactionExternalKey,
                                                final InternalCallContext context) throws InvoiceApiException {
 
-
         if (isInvoiceAdjusted && invoiceItemIdsWithNullAmounts.size() == 0) {
             throw new InvoiceApiException(ErrorCode.INVOICE_ITEMS_ADJUSTMENT_MISSING);
         }
 
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
+        return transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
             @Override
             public InvoicePaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoicePaymentSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
@@ -627,7 +628,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public InvoicePaymentModelDao postChargeback(final UUID paymentId, final String chargebackTransactionExternalKey, final BigDecimal amount, final Currency currency, final InternalCallContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
+        return transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
             @Override
             public InvoicePaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoicePaymentSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
@@ -682,7 +683,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public InvoicePaymentModelDao postChargebackReversal(final UUID paymentId, final String chargebackTransactionExternalKey, final InternalCallContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
+        return transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
             @Override
             public InvoicePaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoicePaymentSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
@@ -718,7 +719,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public InvoiceItemModelDao doCBAComplexity(final InvoiceModelDao invoice, final InternalCallContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
+        return transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
             @Override
             public InvoiceItemModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceItemModelDao cbaNewItem = cbaDao.computeCBAComplexity(invoice, null, entitySqlDaoWrapperFactory, context);
@@ -731,7 +732,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public Map<UUID, BigDecimal> computeItemAdjustments(final String invoiceId, final Map<UUID, BigDecimal> invoiceItemIdsWithNullAmounts, final InternalTenantContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Map<UUID, BigDecimal>>() {
+        return transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Map<UUID, BigDecimal>>() {
             @Override
             public Map<UUID, BigDecimal> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return invoiceDaoHelper.computeItemAdjustments(invoiceId, invoicesTags, entitySqlDaoWrapperFactory, invoiceItemIdsWithNullAmounts, context);
@@ -741,7 +742,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<BigDecimal>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<BigDecimal>() {
             @Override
             public BigDecimal inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return invoiceDaoHelper.getRemainingAmountPaidFromTransaction(invoicePaymentId, entitySqlDaoWrapperFactory, context);
@@ -751,7 +752,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public UUID getAccountIdFromInvoicePaymentId(final UUID invoicePaymentId, final InternalTenantContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<UUID>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<UUID>() {
             @Override
             public UUID inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final UUID accountId = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getAccountIdFromInvoicePaymentId(invoicePaymentId.toString(), context);
@@ -766,7 +767,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoicePaymentModelDao> getChargebacksByAccountId(final UUID accountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
             @Override
             public List<InvoicePaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getChargeBacksByAccountId(accountId.toString(), context);
@@ -776,7 +777,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoicePaymentModelDao> getChargebacksByPaymentId(final UUID paymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoicePaymentModelDao>>() {
             @Override
             public List<InvoicePaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getChargebacksByPaymentId(paymentId.toString(), context);
@@ -786,7 +787,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public InvoicePaymentModelDao getChargebackById(final UUID chargebackId, final InternalTenantContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoicePaymentModelDao>() {
             @Override
             public InvoicePaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoicePaymentModelDao chargeback = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getById(chargebackId.toString(), context);
@@ -801,7 +802,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public InvoiceItemModelDao getExternalChargeById(final UUID externalChargeId, final InternalTenantContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
             @Override
             public InvoiceItemModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceItemSqlDao invoiceItemSqlDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
@@ -814,7 +815,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         });
     }
 
-
     @Override
     public void notifyOfPaymentInit(final InvoicePaymentModelDao invoicePayment, final InternalCallContext context) {
         notifyOfPaymentCompletionInternal(invoicePayment, false, context);
@@ -826,7 +826,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     }
 
     private void notifyOfPaymentCompletionInternal(final InvoicePaymentModelDao invoicePayment, final boolean completion, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoicePaymentSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
@@ -876,7 +876,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public InvoiceItemModelDao getCreditById(final UUID creditId, final InternalTenantContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceItemModelDao>() {
             @Override
             public InvoiceItemModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceItemSqlDao invoiceItemSqlDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
@@ -893,7 +893,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public void deleteCBA(final UUID accountId, final UUID invoiceId, final UUID invoiceItemId, final InternalCallContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -991,7 +991,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public void consumeExstingCBAOnAccountWithUnpaidInvoices(final UUID accountId, final InternalCallContext context) {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 cbaDao.doCBAComplexityFromTransaction(invoicesTags, entitySqlDaoWrapperFactory, context);
@@ -1094,7 +1094,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                     final InternalCallContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -1102,7 +1102,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 // Retrieve the invoice and make sure it belongs to the right account
                 final InvoiceModelDao invoice = transactional.getById(invoiceId.toString(), context);
 
-                if (invoice == null ) {
+                if (invoice == null) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
                 }
 
@@ -1110,7 +1110,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                     throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_STATUS, newStatus, invoiceId, invoice.getStatus());
                 }
 
-
                 transactional.updateStatus(invoiceId.toString(), newStatus.toString(), context);
 
                 cbaDao.doCBAComplexityFromTransaction(invoicesTags, entitySqlDaoWrapperFactory, context);
@@ -1131,8 +1130,8 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
             final BigDecimal rawBalance = InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice);
             final DefaultInvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
                                                                                       rawBalance, invoice.getCurrency(),
-                                                                                                            context.getAccountRecordId(), context.getTenantRecordId(),
-                                                                                                            context.getUserToken());
+                                                                                      context.getAccountRecordId(), context.getTenantRecordId(),
+                                                                                      context.getUserToken());
             eventBus.postFromTransaction(event, entitySqlDaoWrapperFactory.getHandle().getConnection());
         } catch (final EventBusException e) {
             log.error(String.format("Failed to post invoice creation event %s for account %s", invoice.getAccountId()), e);
@@ -1155,7 +1154,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public void createParentChildInvoiceRelation(final InvoiceParentChildModelDao invoiceRelation, final InternalCallContext context) throws InvoiceApiException {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceParentChildrenSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceParentChildrenSqlDao.class);
@@ -1167,7 +1166,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoiceParentChildModelDao> getChildInvoicesByParentInvoiceId(final UUID parentInvoiceId, final InternalCallContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceParentChildModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceParentChildModelDao>>() {
             @Override
             public List<InvoiceParentChildModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceParentChildrenSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceParentChildrenSqlDao.class);
@@ -1180,7 +1179,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     public InvoiceModelDao getParentDraftInvoice(final UUID parentAccountId, final InternalCallContext context) throws InvoiceApiException {
         final List<Tag> invoicesTags = getInvoicesTags(context);
 
-        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
+        return transactionalSqlDao.execute(true, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
             @Override
             public InvoiceModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -1195,7 +1194,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public void updateInvoiceItemAmount(final UUID invoiceItemId, final BigDecimal amount, final InternalCallContext context) throws InvoiceApiException {
-        transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceItemSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
@@ -1203,7 +1202,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 // Retrieve the invoice and make sure it belongs to the right account
                 final InvoiceItemModelDao invoiceItem = transactional.getById(invoiceItemId.toString(), context);
 
-                if (invoiceItem == null ) {
+                if (invoiceItem == null) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_ITEM_NOT_FOUND, invoiceItemId);
                 }
 
@@ -1223,7 +1222,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         final List<Tag> parentInvoicesTags = getInvoicesTags(parentAccountContext);
         final List<Tag> childInvoicesTags = getInvoicesTags(childAccountContext);
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
@@ -1243,16 +1242,16 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                                                             InvoiceStatus.COMMITTED);
                 final String chargeDescription = "Charge to move credit from child to parent account";
                 final InvoiceItem externalChargeItem = new ExternalChargeInvoiceItem(UUIDs.randomUUID(),
-                                                                                 childCreatedDate,
-                                                                                 invoiceForExternalCharge.getId(),
-                                                                                 childAccount.getId(),
-                                                                                 null,
-                                                                                 chargeDescription,
-                                                                                 childCreatedDate.toLocalDate(),
-                                                                                 childCreatedDate.toLocalDate(),
-                                                                                 accountCBA,
-                                                                                 childAccount.getCurrency(),
-                                                                                 null);
+                                                                                     childCreatedDate,
+                                                                                     invoiceForExternalCharge.getId(),
+                                                                                     childAccount.getId(),
+                                                                                     null,
+                                                                                     chargeDescription,
+                                                                                     childCreatedDate.toLocalDate(),
+                                                                                     childCreatedDate.toLocalDate(),
+                                                                                     accountCBA,
+                                                                                     childAccount.getCurrency(),
+                                                                                     null);
                 invoiceForExternalCharge.addInvoiceItem(externalChargeItem);
 
                 // create credit to parent account
@@ -1274,7 +1273,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                                                         childAccount.getCurrency());
                 invoiceForCredit.addInvoiceItem(creditItem);
 
-
                 // save invoices and invoice items
                 final InvoiceModelDao childInvoice = new InvoiceModelDao(invoiceForExternalCharge);
                 createAndRefresh(invoiceSqlDao, childInvoice, childAccountContext);
@@ -1304,7 +1302,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     @Override
     public List<InvoiceItemModelDao> getInvoiceItemsByParentInvoice(final UUID parentInvoiceId, final InternalTenantContext context) throws InvoiceApiException {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceItemModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<InvoiceItemModelDao>>() {
             @Override
             public List<InvoiceItemModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final InvoiceItemSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);

jaxrs/pom.xml 8(+8 -0)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index f0a870a..4f27ef5 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -63,6 +63,14 @@
             <artifactId>swagger-annotations</artifactId>
         </dependency>
         <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-jaxrs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+        </dependency>
+        <dependency>
             <groupId>javax.inject</groupId>
             <artifactId>javax.inject</artifactId>
             <scope>provided</scope>
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 4375643..ca1afdb 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
@@ -23,22 +23,24 @@ import org.killbill.billing.account.api.AccountEmail;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+
+@ApiModel(value="AccountEmail")
 public class AccountEmailJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID accountId;
     @ApiModelProperty(required = true)
     private final String email;
 
     @JsonCreator
-    public AccountEmailJson(@JsonProperty("accountId") final String accountId, @JsonProperty("email") final String email) {
+    public AccountEmailJson(@JsonProperty("accountId") final UUID accountId, @JsonProperty("email") final String email) {
         this.accountId = accountId;
         this.email = email;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
@@ -51,7 +53,7 @@ public class AccountEmailJson extends JsonBase {
         return new AccountEmail() {
             @Override
             public UUID getAccountId() {
-                return UUID.fromString(accountId);
+                return accountId;
             }
 
             @Override
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 d9b0043..8f55507 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
@@ -35,12 +35,13 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Strings;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Account")
 public class AccountJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID accountId;
     private final String externalKey;
     private final BigDecimal accountCBA;
     private final BigDecimal accountBalance;
@@ -49,11 +50,9 @@ public class AccountJson extends JsonBase {
     private final String email;
     private final Integer billCycleDayLocal;
     private final String currency;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String parentAccountId;
+    private final UUID parentAccountId;
     private final Boolean isPaymentDelegatedToParent;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String paymentMethodId;
+    private final UUID paymentMethodId;
     private final DateTime referenceTime;
     private final String timeZone;
     private final String address1;
@@ -73,16 +72,16 @@ public class AccountJson extends JsonBase {
         super(toAuditLogJson(accountAuditLogs == null ? null : accountAuditLogs.getAuditLogsForAccount()));
         this.accountCBA = accountCBA;
         this.accountBalance = accountBalance;
-        this.accountId = account.getId().toString();
+        this.accountId = account.getId();
         this.externalKey = account.getExternalKey();
         this.name = account.getName();
         this.firstNameLength = account.getFirstNameLength();
         this.email = account.getEmail();
         this.billCycleDayLocal = account.getBillCycleDayLocal();
         this.currency = account.getCurrency() != null ? account.getCurrency().toString() : null;
-        this.parentAccountId = account.getParentAccountId() != null ? account.getParentAccountId().toString() : null;
+        this.parentAccountId = account.getParentAccountId();
         this.isPaymentDelegatedToParent = account.isPaymentDelegatedToParent();
-        this.paymentMethodId = account.getPaymentMethodId() != null ? account.getPaymentMethodId().toString() : null;
+        this.paymentMethodId = account.getPaymentMethodId();
         this.referenceTime = account.getReferenceTime();
         this.timeZone = account.getTimeZone() != null ? account.getTimeZone().toString() : null;
         this.address1 = account.getAddress1();
@@ -100,16 +99,16 @@ public class AccountJson extends JsonBase {
     }
 
     @JsonCreator
-    public AccountJson(@JsonProperty("accountId") final String accountId,
+    public AccountJson(@JsonProperty("accountId") final UUID accountId,
                        @JsonProperty("name") final String name,
                        @JsonProperty("firstNameLength") final Integer firstNameLength,
                        @JsonProperty("externalKey") final String externalKey,
                        @JsonProperty("email") final String email,
                        @JsonProperty("billCycleDayLocal") final Integer billCycleDayLocal,
                        @JsonProperty("currency") final String currency,
-                       @JsonProperty("parentAccountId") final String parentAccountId,
+                       @JsonProperty("parentAccountId") final UUID parentAccountId,
                        @JsonProperty("isPaymentDelegatedToParent") final Boolean isPaymentDelegatedToParent,
-                       @JsonProperty("paymentMethodId") final String paymentMethodId,
+                       @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                        @JsonProperty("referenceTime") final DateTime referenceTime,
                        @JsonProperty("timeZone") final String timeZone,
                        @JsonProperty("address1") final String address1,
@@ -205,11 +204,7 @@ public class AccountJson extends JsonBase {
 
             @Override
             public UUID getPaymentMethodId() {
-                if (Strings.emptyToNull(paymentMethodId) == null) {
-                    return null;
-                } else {
-                    return UUID.fromString(paymentMethodId);
-                }
+                return paymentMethodId;
             }
 
             @Override
@@ -279,11 +274,7 @@ public class AccountJson extends JsonBase {
 
             @Override
             public UUID getParentAccountId() {
-                if (Strings.emptyToNull(parentAccountId) == null) {
-                    return null;
-                } else {
-                    return UUID.fromString(parentAccountId);
-                }
+                return parentAccountId;
             }
 
             @Override
@@ -330,7 +321,7 @@ public class AccountJson extends JsonBase {
         return accountBalance;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
@@ -362,7 +353,7 @@ public class AccountJson extends JsonBase {
         return currency;
     }
 
-    public String getParentAccountId() {
+    public UUID getParentAccountId() {
         return parentAccountId;
     }
 
@@ -371,7 +362,7 @@ public class AccountJson extends JsonBase {
         return isPaymentDelegatedToParent;
     }
 
-    public String getPaymentMethodId() {
+    public UUID getPaymentMethodId() {
         return paymentMethodId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountTimelineJson.java
index 0cb8603..b3c5233 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountTimelineJson.java
@@ -39,7 +39,9 @@ import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="AccountTimeline")
 public class AccountTimelineJson {
 
     private final AccountJson account;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AdminPaymentJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AdminPaymentJson.java
index 3ed676e..2dc7170 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AdminPaymentJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AdminPaymentJson.java
@@ -19,7 +19,9 @@ package org.killbill.billing.jaxrs.json;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="AdminPayment")
 public class AdminPaymentJson {
 
     private final String lastSuccessPaymentState;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AuditLogJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AuditLogJson.java
index 05813b1..0352df3 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AuditLogJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AuditLogJson.java
@@ -22,8 +22,10 @@ import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="AuditLog")
 public class AuditLogJson {
 
     private final String changeType;
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 181fa6d..2dd9324 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
@@ -27,8 +27,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import io.swagger.annotations.ApiModel;
 
 // Doesn't extend JsonBase (no audit logs)
+@ApiModel(value="BillingException")
 public class BillingExceptionJson {
 
     private final String className;
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 f594266..1482cf2 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
@@ -30,12 +30,13 @@ 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")
 public class BlockingStateJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String blockedId;
+    private final UUID blockedId;
     private final String stateName;
     private final String service;
     private final Boolean blockChange;
@@ -45,7 +46,7 @@ public class BlockingStateJson extends JsonBase {
     private final BlockingStateType type;
 
     @JsonCreator
-    public BlockingStateJson(@JsonProperty("blockedId") final String blockedId,
+    public BlockingStateJson(@JsonProperty("blockedId") final UUID blockedId,
                              @JsonProperty("stateName") final String stateName,
                              @JsonProperty("service") final String service,
                              @JsonProperty("blockChange") final Boolean blockChange,
@@ -66,7 +67,7 @@ public class BlockingStateJson extends JsonBase {
     }
 
     public BlockingStateJson(final BlockingState input, final AccountAuditLogs accountAuditLogs) {
-        this(input.getBlockedId().toString(),
+        this(input.getBlockedId(),
              input.getStateName(),
              input.getService(),
              input.isBlockChange(),
@@ -78,7 +79,7 @@ public class BlockingStateJson extends JsonBase {
     }
 
 
-    public String getBlockedId() {
+    public UUID getBlockedId() {
         return blockedId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java
index e24a727..660fd04 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java
@@ -23,7 +23,9 @@ import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="BlockPriceOverride")
 public class BlockPriceOverrideJson {
 
     private String unitName;
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 ebc5d70..78927d3 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
@@ -20,6 +20,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -31,21 +32,22 @@ 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="Bundle")
 public class BundleJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID", required = true)
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String bundleId;
+    @ApiModelProperty(required = true)
+    private final UUID accountId;
+    private final UUID bundleId;
     private final String externalKey;
     private final List<SubscriptionJson> subscriptions;
     private final BundleTimelineJson timeline;
 
     @JsonCreator
-    public BundleJson(@JsonProperty("accountId") @Nullable final String accountId,
-                      @JsonProperty("bundleId") @Nullable final String bundleId,
+    public BundleJson(@JsonProperty("accountId") @Nullable final UUID accountId,
+                      @JsonProperty("bundleId") @Nullable final UUID bundleId,
                       @JsonProperty("externalKey") @Nullable final String externalKey,
                       @JsonProperty("subscriptions") @Nullable final List<SubscriptionJson> subscriptions,
                       @JsonProperty("timeline") @Nullable final BundleTimelineJson timeline,
@@ -60,8 +62,8 @@ public class BundleJson extends JsonBase {
 
     public BundleJson(final SubscriptionBundle bundle, @Nullable final Currency currency, @Nullable final AccountAuditLogs accountAuditLogs) throws CatalogApiException {
         super(toAuditLogJson(accountAuditLogs == null ? null : accountAuditLogs.getAuditLogsForBundle(bundle.getId())));
-        this.accountId = bundle.getAccountId().toString();
-        this.bundleId = bundle.getId().toString();
+        this.accountId = bundle.getAccountId();
+        this.bundleId = bundle.getId();
         this.externalKey = bundle.getExternalKey();
         this.subscriptions = new LinkedList<SubscriptionJson>();
         for (final Subscription subscription : bundle.getSubscriptions()) {
@@ -76,11 +78,11 @@ public class BundleJson extends JsonBase {
         return subscriptions;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getBundleId() {
+    public UUID getBundleId() {
         return bundleId;
     }
 
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 569cdfa..765096c 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
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -28,20 +29,20 @@ 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="BundleTimeline")
 public class BundleTimelineJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String bundleId;
+    private final UUID accountId;
+    private final UUID bundleId;
     private final String externalKey;
     private final List<EventSubscriptionJson> events;
 
     @JsonCreator
-    public BundleTimelineJson(@JsonProperty("accountId") @Nullable final String accountId,
-                              @JsonProperty("bundleId") @Nullable final String bundleId,
+    public BundleTimelineJson(@JsonProperty("accountId") @Nullable final UUID accountId,
+                              @JsonProperty("bundleId") @Nullable final UUID bundleId,
                               @JsonProperty("externalKey") @Nullable final String externalKey,
                               @JsonProperty("events") @Nullable final List<EventSubscriptionJson> events,
                               @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
@@ -54,8 +55,8 @@ public class BundleTimelineJson extends JsonBase {
 
     public BundleTimelineJson(final SubscriptionBundleTimeline bundleTimeline, @Nullable final AccountAuditLogs accountAuditLogs) {
         super(toAuditLogJson(accountAuditLogs == null ? null : accountAuditLogs.getAuditLogsForBundle(bundleTimeline.getBundleId())));
-        this.accountId = bundleTimeline.getAccountId().toString();
-        this.bundleId = bundleTimeline.getBundleId().toString();
+        this.accountId = bundleTimeline.getAccountId();
+        this.bundleId = bundleTimeline.getBundleId();
         this.externalKey = bundleTimeline.getExternalKey();
 
         this.events = new LinkedList<EventSubscriptionJson>();
@@ -64,11 +65,11 @@ public class BundleTimelineJson extends JsonBase {
         }
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getBundleId() {
+    public UUID getBundleId() {
         return bundleId;
     }
 
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 55a4375..5a93bc8 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
@@ -53,7 +53,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Catalog")
 public class CatalogJson {
 
     private final String name;
@@ -212,6 +215,7 @@ public class CatalogJson {
         return result;
     }
 
+    @ApiModel(value="Unit")
     public static class UnitJson {
 
         private final String name;
@@ -261,6 +265,7 @@ public class CatalogJson {
 
     }
 
+    @ApiModel(value="Product")
     public static class ProductJson {
 
         private final String type;
@@ -382,6 +387,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="Plan")
     public static class PlanJson {
 
         private final String name;
@@ -473,6 +479,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="TieredBlock")
     public static class TieredBlockJson {
         private final String unit;
         private final String size;
@@ -551,6 +558,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="Limit")
     public static class LimitJson {
         private final String unit;
         private final String max;
@@ -618,6 +626,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="Tier")
     public static class TierJson {
         private final List<TieredBlockJson> blocks;
         private final List<LimitJson> limits;
@@ -696,6 +705,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="Usage")
     public static class UsageJson {
         private final String billingPeriod;
         private final List<TierJson> tiers;
@@ -752,6 +762,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="Phase")
     public static class PhaseJson {
 
         private final String type;
@@ -917,6 +928,8 @@ public class CatalogJson {
         }
     }
 
+
+    @ApiModel(value="Price")
     public static class PriceJson {
 
         private final String currency;
@@ -979,6 +992,7 @@ public class CatalogJson {
         }
     }
 
+    @ApiModel(value="PriceList")
     public static class PriceListJson {
 
         private String name;
@@ -1044,6 +1058,7 @@ public class CatalogJson {
 
     }
 
+    @ApiModel(value="Duration")
     public static class DurationJson {
 
         private final TimeUnit unit;
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 8e72c5f..0ae0281 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,7 +23,9 @@ import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="ComboHostedPaymentPage")
 public class ComboHostedPaymentPageJson extends ComboPaymentJson {
 
     private final HostedPaymentPageFieldsJson hostedPaymentPageFields;
@@ -32,7 +34,7 @@ public class ComboHostedPaymentPageJson extends ComboPaymentJson {
     public ComboHostedPaymentPageJson(@JsonProperty("account") final AccountJson account,
                                       @JsonProperty("paymentMethod") final PaymentMethodJson paymentMethod,
                                       @JsonProperty("hostedPaymentPageFields") final HostedPaymentPageFieldsJson hostedPaymentPageFields,
-                                      @JsonProperty("paymentMethodPluginProperties") final Iterable<PluginPropertyJson> paymentMethodPluginProperties,
+                                      @JsonProperty("paymentMethodPluginProperties") final List<PluginPropertyJson> paymentMethodPluginProperties,
                                       @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(account, paymentMethod, paymentMethodPluginProperties, auditLogs);
         this.hostedPaymentPageFields = 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 be99eca..9828010 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
@@ -23,17 +23,19 @@ import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="ComboPayment")
 public abstract class ComboPaymentJson extends JsonBase {
 
     private final AccountJson account;
     private final PaymentMethodJson paymentMethod;
-    private final Iterable<PluginPropertyJson> paymentMethodPluginProperties;
+    private final List<PluginPropertyJson> paymentMethodPluginProperties;
 
     @JsonCreator
     public ComboPaymentJson(@JsonProperty("account") final AccountJson account,
                             @JsonProperty("paymentMethod") final PaymentMethodJson paymentMethod,
-                            @JsonProperty("paymentMethodPluginProperties") final Iterable<PluginPropertyJson> paymentMethodPluginProperties,
+                            @JsonProperty("paymentMethodPluginProperties") final List<PluginPropertyJson> paymentMethodPluginProperties,
                             @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
         this.account = account;
@@ -49,7 +51,7 @@ public abstract class ComboPaymentJson extends JsonBase {
         return paymentMethod;
     }
 
-    public Iterable<PluginPropertyJson> getPaymentMethodPluginProperties() {
+    public List<PluginPropertyJson> getPaymentMethodPluginProperties() {
         return paymentMethodPluginProperties;
     }
 
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 cde1b73..f7b7b4d 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
@@ -23,18 +23,20 @@ import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="ComboPaymentTransaction")
 public class ComboPaymentTransactionJson extends ComboPaymentJson {
 
     private final PaymentTransactionJson transaction;
-    private final Iterable<PluginPropertyJson> transactionPluginProperties;
+    private final List<PluginPropertyJson> transactionPluginProperties;
 
     @JsonCreator
     public ComboPaymentTransactionJson(@JsonProperty("account") final AccountJson account,
                                        @JsonProperty("paymentMethod") final PaymentMethodJson paymentMethod,
                                        @JsonProperty("transaction") final PaymentTransactionJson transaction,
-                                       @JsonProperty("paymentMethodPluginProperties") final Iterable<PluginPropertyJson> paymentMethodPluginProperties,
-                                       @JsonProperty("transactionPluginProperties") final Iterable<PluginPropertyJson> transactionPluginProperties,
+                                       @JsonProperty("paymentMethodPluginProperties") final List<PluginPropertyJson> paymentMethodPluginProperties,
+                                       @JsonProperty("transactionPluginProperties") final List<PluginPropertyJson> transactionPluginProperties,
                                        @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(account, paymentMethod, paymentMethodPluginProperties, auditLogs);
         this.transaction = transaction;
@@ -53,7 +55,7 @@ public class ComboPaymentTransactionJson extends ComboPaymentJson {
         return null;
     }
 
-    public Iterable<PluginPropertyJson> getTransactionPluginProperties() {
+    public List<PluginPropertyJson> getTransactionPluginProperties() {
         return transactionPluginProperties;
     }
 
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 886b26d..a65fda4 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
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -29,18 +30,19 @@ import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Credit")
 public class CreditJson extends JsonBase {
 
     @ApiModelProperty(required = true)
     private final BigDecimal creditAmount;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String invoiceId;
+    private final UUID invoiceId;
     private final String invoiceNumber;
     private final LocalDate effectiveDate;
-    @ApiModelProperty(dataType = "java.util.UUID", required = true)
-    private final String accountId;
+    @ApiModelProperty(required = true)
+    private final UUID accountId;
     private final String description;
     private final String currency;
 
@@ -48,10 +50,10 @@ public class CreditJson extends JsonBase {
     @JsonCreator
     public CreditJson(@JsonProperty("creditAmount") final BigDecimal creditAmount,
                       @JsonProperty("currency") final String currency,
-                      @JsonProperty("invoiceId") final String invoiceId,
+                      @JsonProperty("invoiceId") final UUID invoiceId,
                       @JsonProperty("invoiceNumber") final String invoiceNumber,
                       @JsonProperty("effectiveDate") final LocalDate effectiveDate,
-                      @JsonProperty("accountId") final String accountId,
+                      @JsonProperty("accountId") final UUID accountId,
                       @JsonProperty("description") final String description,
                       @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
@@ -66,10 +68,10 @@ public class CreditJson extends JsonBase {
 
     public CreditJson(final Invoice invoice, final InvoiceItem credit, final List<AuditLog> auditLogs) {
         super(toAuditLogJson(auditLogs));
-        this.accountId = toString(credit.getAccountId());
+        this.accountId = credit.getAccountId();
         this.creditAmount = credit.getAmount();
         this.currency = credit.getCurrency().name();
-        this.invoiceId = toString(credit.getInvoiceId());
+        this.invoiceId = credit.getInvoiceId();
         this.invoiceNumber = invoice.getInvoiceNumber().toString();
         this.effectiveDate = credit.getStartDate();
         this.description = credit.getDescription();
@@ -83,7 +85,7 @@ public class CreditJson extends JsonBase {
         return creditAmount;
     }
 
-    public String getInvoiceId() {
+    public UUID getInvoiceId() {
         return invoiceId;
     }
 
@@ -95,7 +97,7 @@ public class CreditJson extends JsonBase {
         return effectiveDate;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
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 375b72d..6695075 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
@@ -17,6 +17,7 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -26,14 +27,14 @@ import org.killbill.billing.util.customfield.CustomField;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="CustomField")
 public class CustomFieldJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String customFieldId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String objectId;
+    private final UUID customFieldId;
+    private final UUID objectId;
     private final ObjectType objectType;
     @ApiModelProperty(required = true)
     private final String name;
@@ -41,8 +42,8 @@ public class CustomFieldJson extends JsonBase {
     private final String value;
 
     @JsonCreator
-    public CustomFieldJson(@JsonProperty("customFieldId") final String customFieldId,
-                           @JsonProperty("objectId") final String objectId,
+    public CustomFieldJson(@JsonProperty("customFieldId") final UUID customFieldId,
+                           @JsonProperty("objectId") final UUID objectId,
                            @JsonProperty("objectType") final ObjectType objectType,
                            @JsonProperty("name") @Nullable final String name,
                            @JsonProperty("value") @Nullable final String value,
@@ -56,14 +57,14 @@ public class CustomFieldJson extends JsonBase {
     }
 
     public CustomFieldJson(final CustomField input, @Nullable final List<AuditLog> auditLogs) {
-        this(input.getId().toString(), input.getObjectId().toString(), input.getObjectType(), input.getFieldName(), input.getFieldValue(), toAuditLogJson(auditLogs));
+        this(input.getId(), input.getObjectId(), input.getObjectType(), input.getFieldName(), input.getFieldValue(), toAuditLogJson(auditLogs));
     }
 
-    public String getCustomFieldId() {
+    public UUID getCustomFieldId() {
         return customFieldId;
     }
 
-    public String getObjectId() {
+    public UUID getObjectId() {
         return objectId;
     }
 
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 b8ef5ca..69d093a 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
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
@@ -28,19 +29,20 @@ import org.killbill.billing.payment.plugin.api.GatewayNotification;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="GatewayNotification")
 public class GatewayNotificationJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String kbPaymentId;
+    private final UUID kbPaymentId;
     private final Integer status;
     private final String entity;
     private final Map<String, List<String>> headers;
     private final Map<String, Object> properties;
 
     @JsonCreator
-    public GatewayNotificationJson(@JsonProperty("kbPaymentId") final String kbPaymentId,
+    public GatewayNotificationJson(@JsonProperty("kbPaymentId") final UUID kbPaymentId,
                                    @JsonProperty("status") final Integer status,
                                    @JsonProperty("entity") final String entity,
                                    @JsonProperty("headers") final Map<String, List<String>> headers,
@@ -53,7 +55,7 @@ public class GatewayNotificationJson extends JsonBase {
     }
 
     public GatewayNotificationJson(final GatewayNotification notification) {
-        this.kbPaymentId = notification.getKbPaymentId() == null ? null : notification.getKbPaymentId().toString();
+        this.kbPaymentId = notification.getKbPaymentId();
         this.status = notification.getStatus();
         this.entity = notification.getEntity();
         this.headers = notification.getHeaders();
@@ -78,7 +80,7 @@ public class GatewayNotificationJson extends JsonBase {
         return responseBuilder.build();
     }
 
-    public String getKbPaymentId() {
+    public UUID getKbPaymentId() {
         return 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 a294598..59bcdb4 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
@@ -18,7 +18,9 @@ package org.killbill.billing.jaxrs.json;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="HostedPaymentPageBillingAddress")
 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 3780c27..6631cac 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
@@ -18,7 +18,9 @@ package org.killbill.billing.jaxrs.json;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="HostedPaymentPageCustomer")
 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 470f8f8..7f5b638 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
@@ -20,7 +20,10 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+
+@ApiModel(value="HostedPaymentPageFields")
 public class HostedPaymentPageFieldsJson extends JsonBase {
 
     private final List<PluginPropertyJson> 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 24b292c..dc7134e 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
@@ -18,24 +18,26 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.util.Map;
+import java.util.UUID;
 
 import org.killbill.billing.payment.plugin.api.HostedPaymentPageFormDescriptor;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="HostedPaymentPageFormDescriptor")
 public class HostedPaymentPageFormDescriptorJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String kbAccountId;
+    private final UUID kbAccountId;
     private final String formMethod;
     private final String formUrl;
     private final Map<String, Object> formFields;
     private final Map<String, Object> properties;
 
     @JsonCreator
-    public HostedPaymentPageFormDescriptorJson(@JsonProperty("kbAccountId") final String kbAccountId,
+    public HostedPaymentPageFormDescriptorJson(@JsonProperty("kbAccountId") final UUID kbAccountId,
                                                @JsonProperty("formMethod") final String formMethod,
                                                @JsonProperty("formUrl") final String formUrl,
                                                @JsonProperty("formFields") final Map<String, Object> formFields,
@@ -48,14 +50,14 @@ public class HostedPaymentPageFormDescriptorJson extends JsonBase {
     }
 
     public HostedPaymentPageFormDescriptorJson(final HostedPaymentPageFormDescriptor descriptor) {
-        this.kbAccountId = descriptor.getKbAccountId().toString();
+        this.kbAccountId = descriptor.getKbAccountId();
         this.formMethod = descriptor.getFormMethod();
         this.formUrl = descriptor.getFormUrl();
         this.formFields = propertiesToMap(descriptor.getFormFields());
         this.properties = propertiesToMap(descriptor.getProperties());
     }
 
-    public String getKbAccountId() {
+    public UUID getKbAccountId() {
         return 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 bc82ab3..42493da 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
@@ -18,6 +18,7 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -25,7 +26,9 @@ import org.joda.time.LocalDate;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="InvoiceDryRun")
 public class InvoiceDryRunJson {
 
     private final String dryRunType;
@@ -36,8 +39,8 @@ public class InvoiceDryRunJson {
     private final String billingPeriod;
     private final String priceListName;
     private final LocalDate effectiveDate;
-    private final String subscriptionId;
-    private final String bundleId;
+    private final UUID subscriptionId;
+    private final UUID bundleId;
     private final String billingPolicy;
     private final List<PhasePriceOverrideJson> priceOverrides;
 
@@ -49,8 +52,8 @@ public class InvoiceDryRunJson {
                              @JsonProperty("productCategory") @Nullable final String productCategory,
                              @JsonProperty("billingPeriod") @Nullable final String billingPeriod,
                              @JsonProperty("priceListName") @Nullable final String priceListName,
-                             @JsonProperty("subscriptionId") @Nullable final String subscriptionId,
-                             @JsonProperty("bundleId") @Nullable final String bundleId,
+                             @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("priceOverrides") @Nullable final List<PhasePriceOverrideJson> priceOverrides) {
@@ -96,7 +99,7 @@ public class InvoiceDryRunJson {
         return priceListName;
     }
 
-    public String getSubscriptionId() {
+    public UUID getSubscriptionId() {
         return subscriptionId;
     }
 
@@ -104,7 +107,7 @@ public class InvoiceDryRunJson {
         return effectiveDate;
     }
 
-    public String getBundleId() {
+    public UUID getBundleId() {
         return bundleId;
     }
 
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 2eb503c..9dee36c 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
@@ -16,25 +16,28 @@
 
 package org.killbill.billing.jaxrs.json;
 
+import java.util.UUID;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonGetter;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="InvoiceEmail")
 public class InvoiceEmailJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID accountId;
     private final boolean isNotifiedForInvoices;
 
     @JsonCreator
-    public InvoiceEmailJson(@JsonProperty("accountId") final String accountId,
+    public InvoiceEmailJson(@JsonProperty("accountId") final UUID accountId,
                             @JsonProperty("isNotifiedForInvoices") final boolean isNotifiedForInvoices) {
         this.accountId = accountId;
         this.isNotifiedForInvoices = isNotifiedForInvoices;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return 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 fba3f1e..f19cc88 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
@@ -34,24 +34,21 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="InvoiceItem")
 public class InvoiceItemJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID", required = true)
-    private final String invoiceItemId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String invoiceId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String linkedInvoiceItemId;
-    @ApiModelProperty(dataType = "java.util.UUID", required = true)
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID", required = false)
-    private final String childAccountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String bundleId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String subscriptionId;
+    @ApiModelProperty( required = true)
+    private final UUID invoiceItemId;
+    private final UUID invoiceId;
+    private final UUID linkedInvoiceItemId;
+    @ApiModelProperty(required = true)
+    private final UUID accountId;
+    private final UUID childAccountId;
+    private final UUID bundleId;
+    private final UUID subscriptionId;
     private final String planName;
     private final String phaseName;
     private final String usageName;
@@ -70,13 +67,13 @@ public class InvoiceItemJson extends JsonBase {
     private List<InvoiceItemJson> childItems;
 
     @JsonCreator
-    public InvoiceItemJson(@JsonProperty("invoiceItemId") final String invoiceItemId,
-                           @JsonProperty("invoiceId") final String invoiceId,
-                           @JsonProperty("linkedInvoiceItemId") final String linkedInvoiceItemId,
-                           @JsonProperty("accountId") final String accountId,
-                           @JsonProperty("childAccountId") final String childAccountId,
-                           @JsonProperty("bundleId") final String bundleId,
-                           @JsonProperty("subscriptionId") final String subscriptionId,
+    public InvoiceItemJson(@JsonProperty("invoiceItemId") final UUID invoiceItemId,
+                           @JsonProperty("invoiceId") final UUID invoiceId,
+                           @JsonProperty("linkedInvoiceItemId") final UUID linkedInvoiceItemId,
+                           @JsonProperty("accountId") final UUID accountId,
+                           @JsonProperty("childAccountId") final UUID childAccountId,
+                           @JsonProperty("bundleId") final UUID bundleId,
+                           @JsonProperty("subscriptionId") final UUID subscriptionId,
                            @JsonProperty("planName") final String planName,
                            @JsonProperty("phaseName") final String phaseName,
                            @JsonProperty("usageName") final String usageName,
@@ -121,8 +118,8 @@ public class InvoiceItemJson extends JsonBase {
     }
 
     public InvoiceItemJson(final InvoiceItem item, final List<InvoiceItem> childItems, @Nullable final List<AuditLog> auditLogs) {
-        this(toString(item.getId()), toString(item.getInvoiceId()), toString(item.getLinkedItemId()),
-             toString(item.getAccountId()), toString(item.getChildAccountId()), toString(item.getBundleId()), toString(item.getSubscriptionId()),
+        this(item.getId(), item.getInvoiceId(), item.getLinkedItemId(),
+             item.getAccountId(), item.getChildAccountId(), item.getBundleId(), item.getSubscriptionId(),
              item.getPlanName(), item.getPhaseName(), item.getUsageName(),
              item.getPrettyPlanName(), item.getPrettyPhaseName(), item.getPrettyUsageName(),
              item.getInvoiceItemType().toString(),
@@ -152,17 +149,17 @@ public class InvoiceItemJson extends JsonBase {
 
             @Override
             public UUID getInvoiceId() {
-                return invoiceId != null ? UUID.fromString(invoiceId) : null;
+                return invoiceId;
             }
 
             @Override
             public UUID getAccountId() {
-                return accountId != null ? UUID.fromString(accountId) : null;
+                return accountId;
             }
 
             @Override
             public UUID getChildAccountId() {
-                return childAccountId != null ? UUID.fromString(childAccountId) : null;
+                return childAccountId;
             }
 
             @Override
@@ -192,12 +189,12 @@ public class InvoiceItemJson extends JsonBase {
 
             @Override
             public UUID getBundleId() {
-                return bundleId != null ? UUID.fromString(bundleId) : null;
+                return bundleId;
             }
 
             @Override
             public UUID getSubscriptionId() {
-                return subscriptionId != null ? UUID.fromString(subscriptionId) : null;
+                return subscriptionId;
             }
 
             @Override
@@ -237,7 +234,7 @@ public class InvoiceItemJson extends JsonBase {
 
             @Override
             public UUID getLinkedItemId() {
-                return linkedInvoiceItemId != null ? UUID.fromString(linkedInvoiceItemId) : null;
+                return linkedInvoiceItemId;
             }
 
             @Override
@@ -272,31 +269,31 @@ public class InvoiceItemJson extends JsonBase {
         this(input, null, null);
     }
 
-    public String getInvoiceItemId() {
+    public UUID getInvoiceItemId() {
         return invoiceItemId;
     }
 
-    public String getInvoiceId() {
+    public UUID getInvoiceId() {
         return invoiceId;
     }
 
-    public String getLinkedInvoiceItemId() {
+    public UUID getLinkedInvoiceItemId() {
         return linkedInvoiceItemId;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getChildAccountId() {
+    public UUID getChildAccountId() {
         return childAccountId;
     }
 
-    public String getBundleId() {
+    public UUID getBundleId() {
         return bundleId;
     }
 
-    public String getSubscriptionId() {
+    public UUID getSubscriptionId() {
         return subscriptionId;
     }
 
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 36af2b2..10568e2 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
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs.json;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -35,29 +36,29 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Invoice")
 public class InvoiceJson extends JsonBase {
 
     private final BigDecimal amount;
     private final String currency;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String invoiceId;
+    private final UUID invoiceId;
     private final LocalDate invoiceDate;
     private final LocalDate targetDate;
     private final String invoiceNumber;
     private final BigDecimal balance;
     private final BigDecimal creditAdj;
     private final BigDecimal refundAdj;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID accountId;
     private final List<InvoiceItemJson> items;
     private final String bundleKeys;
     private final List<CreditJson> credits;
     private final String status;
     private final Boolean isParentInvoice;
-    private final String parentInvoiceId;
-    private final String parentAccountId;
+    private final UUID parentInvoiceId;
+    private final UUID parentAccountId;
 
     @JsonCreator
     public InvoiceJson(@JsonProperty("amount") final BigDecimal amount,
@@ -65,18 +66,18 @@ public class InvoiceJson extends JsonBase {
                        @JsonProperty("status") final String status,
                        @JsonProperty("creditAdj") final BigDecimal creditAdj,
                        @JsonProperty("refundAdj") final BigDecimal refundAdj,
-                       @JsonProperty("invoiceId") final String invoiceId,
+                       @JsonProperty("invoiceId") final UUID invoiceId,
                        @JsonProperty("invoiceDate") final LocalDate invoiceDate,
                        @JsonProperty("targetDate") final LocalDate targetDate,
                        @JsonProperty("invoiceNumber") final String invoiceNumber,
                        @JsonProperty("balance") final BigDecimal balance,
-                       @JsonProperty("accountId") final String accountId,
+                       @JsonProperty("accountId") final UUID accountId,
                        @JsonProperty("bundleKeys") final String bundleKeys,
                        @JsonProperty("credits") final List<CreditJson> credits,
                        @JsonProperty("items") final List<InvoiceItemJson> items,
                        @JsonProperty("isParentInvoice") final Boolean isParentInvoice,
-                       @JsonProperty("parentInvoiceId") final String parentInvoiceId,
-                       @JsonProperty("parentAccountId") final String parentAccountId,
+                       @JsonProperty("parentInvoiceId") final UUID parentInvoiceId,
+                       @JsonProperty("parentAccountId") final UUID parentAccountId,
                        @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
         this.amount = amount;
@@ -104,10 +105,10 @@ 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(),
-             input.getId().toString(), input.getInvoiceDate(), input.getTargetDate(), String.valueOf(input.getInvoiceNumber()),
-             input.getBalance(), input.getAccountId().toString(), bundleKeys, credits, null, input.isParentInvoice(),
-             input.getParentInvoiceId() != null ? input.getParentInvoiceId().toString() : null,
-             input.getParentAccountId() != null ? input.getParentAccountId().toString() : null,
+             input.getId(), input.getInvoiceDate(), input.getTargetDate(), String.valueOf(input.getInvoiceNumber()),
+             input.getBalance(), input.getAccountId(), bundleKeys, credits, null, input.isParentInvoice(),
+             input.getParentInvoiceId(),
+             input.getParentAccountId(),
              toAuditLogJson(auditLogs));
     }
 
@@ -133,17 +134,17 @@ public class InvoiceJson extends JsonBase {
         this.status = input.getStatus().toString();
         this.creditAdj = input.getCreditedAmount();
         this.refundAdj = input.getRefundedAmount();
-        this.invoiceId = input.getId().toString();
+        this.invoiceId = input.getId();
         this.invoiceDate = input.getInvoiceDate();
         this.targetDate = input.getTargetDate();
         this.invoiceNumber = input.getInvoiceNumber() == null ? null : String.valueOf(input.getInvoiceNumber());
         this.balance = input.getBalance();
-        this.accountId = input.getAccountId().toString();
+        this.accountId = input.getAccountId();
         this.bundleKeys = null;
         this.credits = null;
         this.isParentInvoice = input.isParentInvoice();
-        this.parentInvoiceId = input.getParentInvoiceId() != null ? input.getParentInvoiceId().toString() : null;
-        this.parentAccountId = input.getParentAccountId() != null ? input.getParentAccountId().toString() : null;
+        this.parentInvoiceId = input.getParentInvoiceId();
+        this.parentAccountId = input.getParentAccountId();
 
     }
 
@@ -155,7 +156,7 @@ public class InvoiceJson extends JsonBase {
         return currency;
     }
 
-    public String getInvoiceId() {
+    public UUID getInvoiceId() {
         return invoiceId;
     }
 
@@ -183,7 +184,7 @@ public class InvoiceJson extends JsonBase {
         return refundAdj;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
@@ -207,11 +208,11 @@ public class InvoiceJson extends JsonBase {
         return isParentInvoice;
     }
 
-    public String getParentInvoiceId() {
+    public UUID getParentInvoiceId() {
         return parentInvoiceId;
     }
 
-    public String getParentAccountId() {
+    public UUID getParentAccountId() {
         return parentAccountId;
     }
 
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 7379469..8697e9a 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
@@ -30,18 +30,19 @@ 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="InvoicePayment")
 public class InvoicePaymentJson extends PaymentJson {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String targetInvoiceId;
+    private final UUID targetInvoiceId;
 
 
     @JsonCreator
-    public InvoicePaymentJson(@JsonProperty("targetInvoiceId") final String targetInvoiceId,
-                              @JsonProperty("accountId") final String accountId,
-                              @JsonProperty("paymentId") final String paymentId,
+    public InvoicePaymentJson(@JsonProperty("targetInvoiceId") final UUID targetInvoiceId,
+                              @JsonProperty("accountId") final UUID accountId,
+                              @JsonProperty("paymentId") final UUID paymentId,
                               @JsonProperty("paymentNumber") final String paymentNumber,
                               @JsonProperty("paymentExternalKey") final String paymentExternalKey,
                               @JsonProperty("authAmount") final BigDecimal authAmount,
@@ -50,7 +51,7 @@ public class InvoicePaymentJson extends PaymentJson {
                               @JsonProperty("refundedAmount") final BigDecimal refundedAmount,
                               @JsonProperty("creditedAmount") final BigDecimal creditedAmount,
                               @JsonProperty("currency") final String currency,
-                              @JsonProperty("paymentMethodId") final String paymentMethodId,
+                              @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                               @JsonProperty("transactions") final List<? extends PaymentTransactionJson> transactions,
                               @JsonProperty("paymentAttempts") final List<PaymentAttemptJson> paymentAttempts,
                               @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
@@ -61,11 +62,11 @@ public class InvoicePaymentJson extends PaymentJson {
     public InvoicePaymentJson(final Payment payment, @Nullable final UUID invoiceId, @Nullable final AccountAuditLogs accountAuditLogs) {
         super(payment, accountAuditLogs);
         //  TODO should build InvoicePaymentTransactionJson instead of PaymentTransactionJson here.
-        this.targetInvoiceId = invoiceId != null ? invoiceId.toString() : null;
+        this.targetInvoiceId = invoiceId;
     }
 
 
-        public String getTargetInvoiceId() {
+        public UUID getTargetInvoiceId() {
         return targetInvoiceId;
     }
 
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 8c03d0e..2635d7a 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
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -26,16 +27,18 @@ import org.joda.time.DateTime;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="InvoicePaymentTransaction")
 public class InvoicePaymentTransactionJson extends PaymentTransactionJson {
 
     private final Boolean isAdjusted;
     private final List<InvoiceItemJson> adjustments;
 
     @JsonCreator
-    public InvoicePaymentTransactionJson(@JsonProperty("transactionId") final String transactionId,
+    public InvoicePaymentTransactionJson(@JsonProperty("transactionId") final UUID transactionId,
                                          @JsonProperty("transactionExternalKey") final String transactionExternalKey,
-                                         @JsonProperty("paymentId") final String paymentId,
+                                         @JsonProperty("paymentId") final UUID paymentId,
                                          @JsonProperty("paymentExternalKey") final String paymentExternalKey,
                                          @JsonProperty("transactionType") final String transactionType,
                                          @JsonProperty("amount") final BigDecimal amount,
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 ca8ec1f..ffcf1d3 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
@@ -23,7 +23,9 @@ import org.killbill.billing.util.nodes.NodeCommandProperty;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="NodeCommand")
 public class NodeCommandJson {
 
     private final boolean systemCommandType;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandPropertyJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandPropertyJson.java
index ef0665b..38cbfe6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandPropertyJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeCommandPropertyJson.java
@@ -21,7 +21,9 @@ import org.killbill.billing.util.nodes.NodeCommandProperty;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="NodeCommandProperty")
 public class NodeCommandPropertyJson extends NodeCommandProperty {
 
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeInfoJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeInfoJson.java
index 62477c9..389640d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeInfoJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NodeInfoJson.java
@@ -23,7 +23,9 @@ import org.joda.time.DateTime;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="NodeInfo")
 public class NodeInfoJson {
 
     private final String nodeName;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
index 2f5fbbe..40e7c5c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
@@ -16,30 +16,33 @@
 
 package org.killbill.billing.jaxrs.json;
 
+import java.util.UUID;
+
 import org.killbill.billing.notification.plugin.api.ExtBusEvent;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 /*
  * Use to communicate back with client after they registered a callback
  */
+
+@ApiModel(value="Notification")
 public class NotificationJson {
 
     private final String eventType;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID accountId;
     private final String objectType;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String objectId;
+    private final UUID objectId;
     private String metaData;
 
     @JsonCreator
     public NotificationJson(@JsonProperty("eventType") final String eventType,
-                            @JsonProperty("accountId") final String accountId,
+                            @JsonProperty("accountId") final UUID accountId,
                             @JsonProperty("objectType") final String objectType,
-                            @JsonProperty("objectId") final String objectId,
+                            @JsonProperty("objectId") final UUID objectId,
                             @JsonProperty("metaData") final String metaData) {
         this.eventType = eventType;
         this.accountId = accountId;
@@ -50,9 +53,9 @@ public class NotificationJson {
 
     public NotificationJson(final ExtBusEvent event) {
         this(event.getEventType().toString(),
-             event.getAccountId() != null ? event.getAccountId().toString() : null,
+             event.getAccountId(),
              event.getObjectType().toString(),
-             event.getObjectId() != null ? event.getObjectId().toString() : null,
+             event.getObjectId(),
              event.getMetaData());
     }
 
@@ -60,7 +63,7 @@ public class NotificationJson {
         return eventType;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
@@ -68,7 +71,7 @@ public class NotificationJson {
         return objectType;
     }
 
-    public String getObjectId() {
+    public UUID getObjectId() {
         return objectId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueConditionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueConditionJson.java
index a190bd2..3b0b302 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueConditionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/OverdueConditionJson.java
@@ -28,7 +28,9 @@ import org.killbill.billing.util.tag.ControlTagType;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="OverdueCondition")
 public class OverdueConditionJson {
 
     private final DurationJson timeSinceEarliestUnpaidInvoiceEqualsOrExceeds;
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 c2284be..1e30ce4 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
@@ -35,7 +35,9 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="Overdue")
 public class OverdueJson {
 
     private final Integer initialReevaluationIntervalDays;
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 0e8a4c4..9a509ab 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
@@ -23,7 +23,9 @@ import org.killbill.billing.overdue.api.OverdueState;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="OverdueStateConfig")
 public class OverdueStateConfigJson {
 
     private final String name;
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 4ab3eab..ef5f7fa 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
@@ -25,7 +25,9 @@ import org.killbill.billing.util.config.definition.PaymentConfig;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="OverdueState")
 public class OverdueStateJson {
 
     private final String name;
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 17763cf..6206614 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
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -31,16 +32,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(description = "Payment attempt")
+@ApiModel(value="PaymentAttempt")
 public class PaymentAttemptJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String paymentMethodId;
+    private final UUID accountId;
+    private final UUID paymentMethodId;
     private final String paymentExternalKey;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String transactionId;
+    private final UUID transactionId;
     private final String transactionExternalKey;
     @ApiModelProperty(dataType = "org.killbill.billing.payment.api.TransactionType")
     private final String transactionType;
@@ -56,10 +54,10 @@ public class PaymentAttemptJson extends JsonBase {
     private final List<PluginPropertyJson> pluginProperties;
 
     @JsonCreator
-    public PaymentAttemptJson(@JsonProperty("accountId") final String accountId,
-                              @JsonProperty("paymentMethodId") final String paymentMethodId,
+    public PaymentAttemptJson(@JsonProperty("accountId") final UUID accountId,
+                              @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                               @JsonProperty("paymentExternalKey") final String paymentExternalKey,
-                              @JsonProperty("transactionId") final String transactionId,
+                              @JsonProperty("transactionId") final UUID transactionId,
                               @JsonProperty("transactionExternalKey") final String transactionExternalKey,
                               @JsonProperty("transactionType") final String transactionType,
                               @JsonProperty("effectiveDate") final DateTime effectiveDate,
@@ -85,11 +83,11 @@ public class PaymentAttemptJson extends JsonBase {
     }
 
     public PaymentAttemptJson(final PaymentAttempt paymentAttempt, final String paymentExternalKey, @Nullable final List<AuditLog> attemptsLogs) {
-        this(paymentAttempt.getAccountId().toString(),
+        this(paymentAttempt.getAccountId(),
              // Could be null if aborted in the priorCall
-             paymentAttempt.getPaymentMethodId() != null ? paymentAttempt.getPaymentMethodId().toString() : null,
+             paymentAttempt.getPaymentMethodId(),
              paymentExternalKey,
-             paymentAttempt.getTransactionId() != null ? paymentAttempt.getTransactionId().toString() : null,
+             paymentAttempt.getTransactionId(),
              paymentAttempt.getTransactionExternalKey(),
              paymentAttempt.getTransactionType().toString(),
              paymentAttempt.getEffectiveDate(),
@@ -101,11 +99,11 @@ public class PaymentAttemptJson extends JsonBase {
              toAuditLogJson(attemptsLogs));
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getPaymentMethodId() {
+    public UUID getPaymentMethodId() {
         return paymentMethodId;
     }
 
@@ -113,7 +111,7 @@ public class PaymentAttemptJson extends JsonBase {
         return paymentExternalKey;
     }
 
-    public String getTransactionId() {
+    public UUID getTransactionId() {
         return transactionId;
     }
 
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 4a605fa..674d00e 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
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -32,14 +33,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Payment")
 public class PaymentJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String paymentId;
+    private final UUID accountId;
+    private final UUID paymentId;
     private final String paymentNumber;
     private final String paymentExternalKey;
     private final BigDecimal authAmount;
@@ -48,14 +49,13 @@ public class PaymentJson extends JsonBase {
     private final BigDecimal refundedAmount;
     private final BigDecimal creditedAmount;
     private final String currency;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String paymentMethodId;
+    private final UUID paymentMethodId;
     private final List<? extends PaymentTransactionJson> transactions;
     private final List<PaymentAttemptJson> paymentAttempts;
 
     @JsonCreator
-    public PaymentJson(@JsonProperty("accountId") final String accountId,
-                       @JsonProperty("paymentId") final String paymentId,
+    public PaymentJson(@JsonProperty("accountId") final UUID accountId,
+                       @JsonProperty("paymentId") final UUID paymentId,
                        @JsonProperty("paymentNumber") final String paymentNumber,
                        @JsonProperty("paymentExternalKey") final String paymentExternalKey,
                        @JsonProperty("authAmount") final BigDecimal authAmount,
@@ -64,7 +64,7 @@ public class PaymentJson extends JsonBase {
                        @JsonProperty("refundedAmount") final BigDecimal refundedAmount,
                        @JsonProperty("creditedAmount") final BigDecimal creditedAmount,
                        @JsonProperty("currency") final String currency,
-                       @JsonProperty("paymentMethodId") final String paymentMethodId,
+                       @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                        @JsonProperty("transactions") final List<? extends PaymentTransactionJson> transactions,
                        @JsonProperty("paymentAttempts") final List<PaymentAttemptJson> paymentAttempts,
                        @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
@@ -85,8 +85,8 @@ public class PaymentJson extends JsonBase {
     }
 
     public PaymentJson(final Payment dp, @Nullable final AccountAuditLogs accountAuditLogs) {
-        this(dp.getAccountId().toString(),
-             dp.getId().toString(),
+        this(dp.getAccountId(),
+             dp.getId(),
              dp.getPaymentNumber().toString(),
              dp.getExternalKey(),
              dp.getAuthAmount(),
@@ -95,7 +95,7 @@ public class PaymentJson extends JsonBase {
              dp.getRefundedAmount(),
              dp.getCreditedAmount(),
              dp.getCurrency() != null ? dp.getCurrency().toString() : null,
-             dp.getPaymentMethodId() != null ? dp.getPaymentMethodId().toString() : null,
+             dp.getPaymentMethodId(),
              getTransactions(dp.getTransactions(), dp.getExternalKey(), accountAuditLogs),
              getAttempts(dp.getPaymentAttempts(), dp.getExternalKey(), accountAuditLogs),
              toAuditLogJson(accountAuditLogs == null ? null : accountAuditLogs.getAuditLogsForPayment(dp.getId())));
@@ -125,11 +125,11 @@ public class PaymentJson extends JsonBase {
                                                        )) : null;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getPaymentId() {
+    public UUID getPaymentId() {
         return paymentId;
     }
 
@@ -165,7 +165,7 @@ public class PaymentJson extends JsonBase {
         return currency;
     }
 
-    public String getPaymentMethodId() {
+    public UUID getPaymentMethodId() {
         return paymentMethodId;
     }
 
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 6a6d997..0f72911 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
@@ -37,23 +37,23 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="PaymentMethod")
 public class PaymentMethodJson extends JsonBase {
 
     private final String externalKey;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String paymentMethodId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
+    private final UUID paymentMethodId;
+    private final UUID accountId;
     private final Boolean isDefault;
     private final String pluginName;
     private final PaymentMethodPluginDetailJson pluginInfo;
 
     @JsonCreator
-    public PaymentMethodJson(@JsonProperty("paymentMethodId") final String paymentMethodId,
+    public PaymentMethodJson(@JsonProperty("paymentMethodId") final UUID paymentMethodId,
                              @JsonProperty("externalKey") final String externalKey,
-                             @JsonProperty("accountId") final String accountId,
+                             @JsonProperty("accountId") final UUID accountId,
                              @JsonProperty("isDefault") final Boolean isDefault,
                              @JsonProperty("pluginName") final String pluginName,
                              @JsonProperty("pluginInfo") @Nullable final PaymentMethodPluginDetailJson pluginInfo,
@@ -86,11 +86,11 @@ public class PaymentMethodJson extends JsonBase {
                                                                  pluginDetail.isDefaultPaymentMethod(),
                                                                  properties);
         }
-        return new PaymentMethodJson(in.getId().toString(), in.getExternalKey(), account.getId().toString(), isDefault, in.getPluginName(),
+        return new PaymentMethodJson(in.getId(), in.getExternalKey(), account.getId(), isDefault, in.getPluginName(),
                                      pluginDetailJson, toAuditLogJson(accountAuditLogs == null ? null : accountAuditLogs.getAuditLogsForPaymentMethod(in.getId())));
     }
 
-    public PaymentMethod toPaymentMethod(final String accountId) {
+    public PaymentMethod toPaymentMethod(final UUID accountId) {
         return new PaymentMethod() {
             @Override
             public Boolean isActive() {
@@ -104,7 +104,7 @@ public class PaymentMethodJson extends JsonBase {
 
             @Override
             public UUID getId() {
-                return paymentMethodId != null ? UUID.fromString(paymentMethodId) : null;
+                return paymentMethodId;
             }
 
             @Override
@@ -124,7 +124,7 @@ public class PaymentMethodJson extends JsonBase {
 
             @Override
             public UUID getAccountId() {
-                return UUID.fromString(accountId);
+                return accountId;
             }
 
             @Override
@@ -132,7 +132,7 @@ public class PaymentMethodJson extends JsonBase {
                 return new PaymentMethodPlugin() {
                     @Override
                     public UUID getKbPaymentMethodId() {
-                        return paymentMethodId == null ? null : UUID.fromString(paymentMethodId);
+                        return paymentMethodId;
                     }
 
                     @Override
@@ -162,11 +162,11 @@ public class PaymentMethodJson extends JsonBase {
         };
     }
 
-    public String getPaymentMethodId() {
+    public UUID getPaymentMethodId() {
         return paymentMethodId;
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
@@ -240,6 +240,8 @@ public class PaymentMethodJson extends JsonBase {
         return result;
     }
 
+
+    @ApiModel(value="PaymentMethodPluginDetail")
     public static class PaymentMethodPluginDetailJson {
 
         private final String externalPaymentMethodId;
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 be81a3a..7b6c89c 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
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -30,14 +31,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-@ApiModel(description = "Payment transaction")
+@ApiModel(value="PaymentTransaction")
 public class PaymentTransactionJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String transactionId;
+    private final UUID transactionId;
     private final String transactionExternalKey;
-    @ApiModelProperty(value = "Associated payment id, required when notifying state transitions", dataType = "java.util.UUID")
-    private final String paymentId;
+    @ApiModelProperty(value = "Associated payment id, required when notifying state transitions")
+    private final UUID paymentId;
     private final String paymentExternalKey;
     @ApiModelProperty(dataType = "org.killbill.billing.payment.api.TransactionType")
     private final String transactionType;
@@ -59,9 +59,9 @@ public class PaymentTransactionJson extends JsonBase {
     private final List<PluginPropertyJson> properties;
 
     @JsonCreator
-    public PaymentTransactionJson(@JsonProperty("transactionId") final String transactionId,
+    public PaymentTransactionJson(@JsonProperty("transactionId") final UUID transactionId,
                                   @JsonProperty("transactionExternalKey") final String transactionExternalKey,
-                                  @JsonProperty("paymentId") final String paymentId,
+                                  @JsonProperty("paymentId") final UUID paymentId,
                                   @JsonProperty("paymentExternalKey") final String paymentExternalKey,
                                   @JsonProperty("transactionType") final String transactionType,
                                   @JsonProperty("amount") final BigDecimal amount,
@@ -96,9 +96,9 @@ public class PaymentTransactionJson extends JsonBase {
     }
 
     public PaymentTransactionJson(final PaymentTransaction transaction, final String paymentExternalKey, @Nullable final List<AuditLog> transactionLogs) {
-        this(transaction.getId().toString(),
+        this(transaction.getId(),
              transaction.getExternalKey(),
-             transaction.getPaymentId().toString(),
+             transaction.getPaymentId(),
              paymentExternalKey,
              transaction.getTransactionType().toString(),
              transaction.getAmount(),
@@ -115,11 +115,11 @@ public class PaymentTransactionJson extends JsonBase {
              toAuditLogJson(transactionLogs));
     }
 
-    public String getTransactionId() {
+    public UUID getTransactionId() {
         return transactionId;
     }
 
-    public String getPaymentId() {
+    public UUID getPaymentId() {
         return paymentId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index 77d27f4..087d44f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -46,7 +46,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="PhasePriceOverride")
 public class PhasePriceOverrideJson {
 
 
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 371d9f3..50f7350 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
@@ -31,7 +31,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="PlanDetail")
 public class PlanDetailJson {
 
     final String product;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginInfoJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginInfoJson.java
index 13e4bbc..6d10169 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginInfoJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginInfoJson.java
@@ -27,7 +27,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="PluginInfo")
 public class PluginInfoJson {
 
     private final String bundleSymbolicName;
@@ -105,6 +107,7 @@ public class PluginInfoJson {
         return services;
     }
 
+    @ApiModel(value="PluginServiceInfo")
     public static class PluginServiceInfoJson {
 
         private final String serviceTypeName;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginPropertyJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginPropertyJson.java
index 40c02c5..1eed1fb 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginPropertyJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PluginPropertyJson.java
@@ -21,7 +21,9 @@ import org.killbill.billing.payment.api.PluginProperty;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="PluginProperty")
 public class PluginPropertyJson {
 
     private final String key;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java
index f3a9ce4..2158431 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java
@@ -30,7 +30,9 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="ProfilingData")
 public class ProfilingDataJson {
 
     private final List<ProfilingDataJsonItem> rawData;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RoleDefinitionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RoleDefinitionJson.java
index 1417203..27730e5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RoleDefinitionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RoleDefinitionJson.java
@@ -21,8 +21,10 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="RoleDefinition")
 public class RoleDefinitionJson {
 
     @ApiModelProperty(required = true)
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java
index f07ac02..64dce49 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java
@@ -17,6 +17,7 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
+import java.util.UUID;
 
 import org.joda.time.LocalDate;
 import org.killbill.billing.usage.api.RolledUpUnit;
@@ -27,18 +28,19 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="RolledUpUsage")
 public class RolledUpUsageJson {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String subscriptionId;
+    private final UUID subscriptionId;
     private final LocalDate startDate;
     private final LocalDate endDate;
     private final List<RolledUpUnitJson> rolledUpUnits;
 
     @JsonCreator
-    public RolledUpUsageJson(@JsonProperty("subscriptionId") final String subscriptionId,
+    public RolledUpUsageJson(@JsonProperty("subscriptionId") final UUID subscriptionId,
                              @JsonProperty("startDate") final LocalDate startDate,
                              @JsonProperty("endDate") final LocalDate endDate,
                              @JsonProperty("rolledUpUnits") final List<RolledUpUnitJson> rolledUpUnits) {
@@ -49,7 +51,7 @@ public class RolledUpUsageJson {
     }
 
     public RolledUpUsageJson(final RolledUpUsage input) {
-        this(input.getSubscriptionId().toString(), input.getStart(), input.getEnd(), ImmutableList.copyOf(Iterables.transform(input.getRolledUpUnits(), new Function<RolledUpUnit, RolledUpUnitJson>() {
+        this(input.getSubscriptionId(), input.getStart(), input.getEnd(), ImmutableList.copyOf(Iterables.transform(input.getRolledUpUnits(), new Function<RolledUpUnit, RolledUpUnitJson>() {
             @Override
             public RolledUpUnitJson apply(final RolledUpUnit input) {
                 return new RolledUpUnitJson(input);
@@ -57,7 +59,7 @@ public class RolledUpUsageJson {
         })));
     }
 
-    public String getSubscriptionId() {
+    public UUID getSubscriptionId() {
         return subscriptionId;
     }
 
@@ -73,6 +75,7 @@ public class RolledUpUsageJson {
         return rolledUpUnits;
     }
 
+    @ApiModel(value="RolledUpUnit")
     public static class RolledUpUnitJson {
 
         private final String unitType;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SessionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SessionJson.java
index 1e28fbf..7f0c241 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SessionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SessionJson.java
@@ -22,8 +22,10 @@ import org.joda.time.DateTimeZone;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Session")
 public class SessionJson {
 
     private final String id;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SimplePlanJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SimplePlanJson.java
index 1c9bb24..2b985b6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SimplePlanJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SimplePlanJson.java
@@ -27,7 +27,9 @@ import org.killbill.billing.catalog.api.TimeUnit;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="SimplePlan")
 public class SimplePlanJson {
 
     private final String planId;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubjectJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubjectJson.java
index 7f95d87..a415acd 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubjectJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubjectJson.java
@@ -23,7 +23,9 @@ import org.apache.shiro.subject.Subject;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="Subject")
 public class SubjectJson {
 
     private final String principal;
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 8afb59e..cd3eae0 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
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -41,16 +42,15 @@ import org.killbill.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Subscription")
 public class SubscriptionJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String accountId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String bundleId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String subscriptionId;
+    private final UUID accountId;
+    private final UUID bundleId;
+    private final UUID subscriptionId;
     private final String externalKey;
     private final LocalDate startDate;
     @ApiModelProperty(required = true)
@@ -79,9 +79,10 @@ public class SubscriptionJson extends JsonBase {
     private final List<EventSubscriptionJson> events;
     private final List<PhasePriceOverrideJson> priceOverrides;
 
+    @ApiModel(value="EventSubscription")
     public static class EventSubscriptionJson extends JsonBase {
 
-        private final String eventId;
+        private final UUID eventId;
         private final String billingPeriod;
         private final LocalDate effectiveDate;
         private final String plan;
@@ -96,7 +97,7 @@ public class SubscriptionJson extends JsonBase {
         private final String serviceStateName;
 
         @JsonCreator
-        public EventSubscriptionJson(@JsonProperty("eventId") final String eventId,
+        public EventSubscriptionJson(@JsonProperty("eventId") final UUID eventId,
                                      @JsonProperty("billingPeriod") final String billingPeriod,
                                      @JsonProperty("effectiveDate") final LocalDate effectiveDate,
                                      @JsonProperty("plan") final String plan,
@@ -132,7 +133,7 @@ public class SubscriptionJson extends JsonBase {
             final Product product = subscriptionEvent.getNextProduct() != null ? subscriptionEvent.getNextProduct() : subscriptionEvent.getPrevProduct();
             final PriceList priceList = subscriptionEvent.getNextPriceList() != null ? subscriptionEvent.getNextPriceList() : subscriptionEvent.getPrevPriceList();
             final PlanPhase phase = subscriptionEvent.getNextPhase() != null ? subscriptionEvent.getNextPhase() : subscriptionEvent.getPrevPhase();
-            this.eventId = subscriptionEvent.getId().toString();
+            this.eventId = subscriptionEvent.getId();
             this.billingPeriod = billingPeriod != null ? billingPeriod.toString() : null;
             this.effectiveDate = subscriptionEvent.getEffectiveDate();
             this.plan = plan != null ? plan.getName() : null;
@@ -160,7 +161,7 @@ public class SubscriptionJson extends JsonBase {
             throw new IllegalStateException("Unepxected objectType " + subscriptionEventObjectType + " for SubscriptionEvent " + subscriptionEvent.getId());
         }
 
-        public String getEventId() {
+        public UUID getEventId() {
             return eventId;
         }
 
@@ -297,9 +298,9 @@ public class SubscriptionJson extends JsonBase {
     }
 
     @JsonCreator
-    public SubscriptionJson(@JsonProperty("accountId") @Nullable final String accountId,
-                            @JsonProperty("bundleId") @Nullable final String bundleId,
-                            @JsonProperty("subscriptionId") @Nullable final String subscriptionId,
+    public SubscriptionJson(@JsonProperty("accountId") @Nullable final UUID accountId,
+                            @JsonProperty("bundleId") @Nullable final UUID bundleId,
+                            @JsonProperty("subscriptionId") @Nullable final UUID subscriptionId,
                             @JsonProperty("externalKey") @Nullable final String externalKey,
                             @JsonProperty("startDate") @Nullable final LocalDate startDate,
                             @JsonProperty("productName") @Nullable final String productName,
@@ -387,9 +388,9 @@ public class SubscriptionJson extends JsonBase {
         this.billingStartDate = subscription.getBillingStartDate();
         this.billingEndDate = subscription.getBillingEndDate();
         this.billCycleDayLocal = subscription.getBillCycleDayLocal();
-        this.accountId = subscription.getAccountId().toString();
-        this.bundleId = subscription.getBundleId().toString();
-        this.subscriptionId = subscription.getId().toString();
+        this.accountId = subscription.getAccountId();
+        this.bundleId = subscription.getBundleId();
+        this.subscriptionId = subscription.getId();
         this.externalKey = subscription.getExternalKey();
         this.events = new LinkedList<EventSubscriptionJson>();
         // We fill the catalog info every time we get the currency from the account (even if this is not overridden Plan)
@@ -420,15 +421,15 @@ public class SubscriptionJson extends JsonBase {
         }
     }
 
-    public String getAccountId() {
+    public UUID getAccountId() {
         return accountId;
     }
 
-    public String getBundleId() {
+    public UUID getBundleId() {
         return bundleId;
     }
 
-    public String getSubscriptionId() {
+    public UUID getSubscriptionId() {
         return subscriptionId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java
index 23cc0e8..c961eb4 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java
@@ -31,19 +31,21 @@ import com.google.common.base.Function;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="SubscriptionUsageRecord")
 public class SubscriptionUsageRecordJson {
 
-    @ApiModelProperty(dataType = "java.util.UUID", required = true)
-    private final String subscriptionId;
+    @ApiModelProperty(required = true)
+    private final UUID subscriptionId;
     @ApiModelProperty(required = true)
     private final List<UnitUsageRecordJson> unitUsageRecords;
     @ApiModelProperty(required = false)
     private final String trackingId;
 
     @JsonCreator
-    public SubscriptionUsageRecordJson(@JsonProperty("subscriptionId") final String subscriptionId,
+    public SubscriptionUsageRecordJson(@JsonProperty("subscriptionId") final UUID subscriptionId,
                                        @JsonProperty("trackingId") final String trackingId,
                                        @JsonProperty("unitUsageRecords") final List<UnitUsageRecordJson> unitUsageRecords) {
         this.subscriptionId = subscriptionId;
@@ -51,7 +53,7 @@ public class SubscriptionUsageRecordJson {
         this.unitUsageRecords = unitUsageRecords;
     }
 
-    public String getSubscriptionId() {
+    public UUID getSubscriptionId() {
         return subscriptionId;
     }
 
@@ -63,6 +65,7 @@ public class SubscriptionUsageRecordJson {
         return trackingId;
     }
 
+    @ApiModel(value="UnitUsageRecord")
     public static class UnitUsageRecordJson {
 
         private final String unitType;
@@ -94,6 +97,7 @@ public class SubscriptionUsageRecordJson {
         }
     }
 
+    @ApiModel(value="UsageRecord")
     public static class UsageRecordJson {
 
         private final LocalDate recordDate;
@@ -126,7 +130,7 @@ public class SubscriptionUsageRecordJson {
                 return input.toUnitUsageRecord();
             }
         }));
-        final SubscriptionUsageRecord result = new SubscriptionUsageRecord(UUID.fromString(subscriptionId), trackingId, tmp);
+        final SubscriptionUsageRecord result = new SubscriptionUsageRecord(subscriptionId, trackingId, tmp);
         return result;
     }
 }
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 779931c..687173d 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
@@ -18,6 +18,7 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -31,12 +32,13 @@ import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="TagDefinition")
 public class TagDefinitionJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String id;
+    private final UUID id;
     private final Boolean isControlTag;
     @ApiModelProperty(required = true)
     private final String name;
@@ -45,7 +47,7 @@ public class TagDefinitionJson extends JsonBase {
     private final Set<String> applicableObjectTypes;
 
     @JsonCreator
-    public TagDefinitionJson(@JsonProperty("id") final String id,
+    public TagDefinitionJson(@JsonProperty("id") final UUID id,
                              @JsonProperty("isControlTag") final Boolean isControlTag,
                              @JsonProperty("name") final String name,
                              @JsonProperty("description") @Nullable final String description,
@@ -60,7 +62,7 @@ public class TagDefinitionJson extends JsonBase {
     }
 
     public TagDefinitionJson(final TagDefinition tagDefinition, @Nullable final List<AuditLog> auditLogs) {
-        this(tagDefinition.getId().toString(),
+        this(tagDefinition.getId(),
              tagDefinition.isControlTag(),
              tagDefinition.getName(),
              tagDefinition.getDescription(),
@@ -77,7 +79,7 @@ public class TagDefinitionJson extends JsonBase {
              toAuditLogJson(auditLogs));
     }
 
-    public String getId() {
+    public UUID getId() {
         return id;
     }
 
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 2b4f729..67681d1 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
@@ -17,6 +17,7 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.util.List;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -27,25 +28,24 @@ import org.killbill.billing.util.tag.TagDefinition;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Tag")
 public class TagJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String tagId;
+    private final UUID tagId;
     @ApiModelProperty(dataType = "org.killbill.billing.ObjectType")
     private final ObjectType objectType;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String objectId;
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String tagDefinitionId;
+    private final UUID objectId;
+    private final UUID tagDefinitionId;
     private final String tagDefinitionName;
 
     @JsonCreator
-    public TagJson(@JsonProperty("tagId") final String tagId,
+    public TagJson(@JsonProperty("tagId") final UUID tagId,
                    @JsonProperty("objectType") final ObjectType objectType,
-                   @JsonProperty("objectId") final String objectId,
-                   @JsonProperty("tagDefinitionId") final String tagDefinitionId,
+                   @JsonProperty("objectId") final UUID objectId,
+                   @JsonProperty("tagDefinitionId") final UUID tagDefinitionId,
                    @JsonProperty("tagDefinitionName") final String tagDefinitionName,
                    @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
@@ -57,10 +57,10 @@ public class TagJson extends JsonBase {
     }
 
     public TagJson(final Tag tag, final TagDefinition tagDefinition, @Nullable final List<AuditLog> auditLogs) {
-        this(tag.getId().toString(), tag.getObjectType(), tag.getObjectId().toString(), tagDefinition.getId().toString(), tagDefinition.getName(), toAuditLogJson(auditLogs));
+        this(tag.getId(), tag.getObjectType(), tag.getObjectId(), tagDefinition.getId(), tagDefinition.getName(), toAuditLogJson(auditLogs));
     }
 
-    public String getTagId() {
+    public UUID getTagId() {
         return tagId;
     }
 
@@ -68,7 +68,7 @@ public class TagJson extends JsonBase {
         return objectType;
     }
 
-    public String getTagDefinitionId() {
+    public UUID getTagDefinitionId() {
         return tagDefinitionId;
     }
 
@@ -76,7 +76,7 @@ public class TagJson extends JsonBase {
         return tagDefinitionName;
     }
 
-    public String getObjectId() {
+    public UUID getObjectId() {
         return objectId;
     }
 
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 c6273b2..615ccf0 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
@@ -16,17 +16,20 @@
 
 package org.killbill.billing.jaxrs.json;
 
+import java.util.UUID;
+
 import org.killbill.billing.tenant.api.Tenant;
 import org.killbill.billing.tenant.api.TenantData;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="Tenant")
 public class TenantJson extends JsonBase {
 
-    @ApiModelProperty(dataType = "java.util.UUID")
-    private final String tenantId;
+    private final UUID tenantId;
     private final String externalKey;
     @ApiModelProperty(required = true)
     private final String apiKey;
@@ -34,7 +37,7 @@ public class TenantJson extends JsonBase {
     private final String apiSecret;
 
     @JsonCreator
-    public TenantJson(@JsonProperty("tenantId") final String tenantId,
+    public TenantJson(@JsonProperty("tenantId") final UUID tenantId,
                       @JsonProperty("externalKey") final String externalKey,
                       @JsonProperty("apiKey") final String apiKey,
                       @JsonProperty("apiSecret") final String apiSecret) {
@@ -45,7 +48,7 @@ public class TenantJson extends JsonBase {
     }
 
     public TenantJson(final Tenant tenant) {
-        this(tenant.getId().toString(), tenant.getExternalKey(), tenant.getApiKey(), tenant.getApiSecret());
+        this(tenant.getId(), tenant.getExternalKey(), tenant.getApiKey(), tenant.getApiSecret());
     }
 
     public TenantData toTenantData() {
@@ -67,7 +70,7 @@ public class TenantJson extends JsonBase {
         };
     }
 
-    public String getTenantId() {
+    public UUID getTenantId() {
         return tenantId;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantKeyJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantKeyJson.java
index f3d3b3d..c1a38e0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantKeyJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TenantKeyJson.java
@@ -20,7 +20,9 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="TenantKey")
 public class TenantKeyJson {
 
     private final String key;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java
index c60c499..7e3f8d2 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java
@@ -21,7 +21,9 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="TierPriceOverride")
 public class TierPriceOverrideJson {
 
     private final List<BlockPriceOverrideJson> blockPriceOverrides;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java
index bbf1a50..9a2ea42 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java
@@ -27,7 +27,9 @@ import org.killbill.billing.catalog.api.UsageType;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 
+@ApiModel(value="UsagePriceOverride")
 public class UsagePriceOverrideJson {
 
     private final String usageName;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UserRolesJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UserRolesJson.java
index 7cdf4fd..16c6c54 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UserRolesJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UserRolesJson.java
@@ -21,8 +21,10 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+@ApiModel(value="UserRoles")
 public class UserRolesJson {
 
     @ApiModelProperty(required = true)
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 29475d4..23aa22f 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
@@ -139,14 +139,17 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 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 io.swagger.annotations.Authorization;
+import io.swagger.annotations.BasicAuthDefinition;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.ACCOUNTS_PATH)
-@Api(value = JaxrsResource.ACCOUNTS_PATH, description = "Operations on accounts")
+@Api(value = JaxrsResource.ACCOUNTS_PATH, description = "Operations on accounts", tags="Account")
 public class AccountResource extends JaxRsResourceBase {
 
     private static final String ID_PARAM_NAME = "accountId";
@@ -192,12 +195,11 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve an account by id", response = AccountJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getAccount(@PathParam("accountId") final String accountIdStr,
+    public Response getAccount(@PathParam("accountId") final UUID accountId,
                                @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,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(account.getId(), auditMode.getLevel(), tenantContext);
@@ -272,12 +274,11 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve bundles for account", response = BundleJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getAccountBundles(@PathParam("accountId") final String accountIdStr,
+    public Response getAccountBundles(@PathParam("accountId") final UUID accountId,
                                       @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
                                       @QueryParam(QUERY_BUNDLES_FILTER) final String bundlesFilter,
                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, SubscriptionApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
@@ -322,7 +323,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(@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,
@@ -376,7 +377,7 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Update account")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account data supplied")})
     public Response updateAccount(final AccountJson json,
-                                  @PathParam("accountId") final String accountIdStr,
+                                  @PathParam("accountId") final UUID accountId,
                                   @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,
@@ -384,14 +385,13 @@ public class AccountResource extends JaxRsResourceBase {
                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
         verifyNonNullOrEmpty(json, "AccountJson body should be specified");
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final Account data = json.toAccount(accountId);
         if (treatNullValueAsReset) {
             accountUserApi.updateAccount(data, context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
         } else {
             accountUserApi.updateAccount(accountId, data, context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
         }
-        return getAccount(accountIdStr, false, false, new AuditMode(AuditLevel.NONE.toString()), request);
+        return getAccount(accountId, false, false, new AuditMode(AuditLevel.NONE.toString()), request);
     }
 
 
@@ -401,7 +401,7 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Close account")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response closeAccount(@PathParam(QUERY_ACCOUNT_ID) final String accountIdStr,
+    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,
                                  @QueryParam(QUERY_ITEM_ADJUST_UNPAID_INVOICES) @DefaultValue("false") final Boolean itemAdjustUnpaidInvoices,
@@ -410,7 +410,6 @@ public class AccountResource extends JaxRsResourceBase {
                                  @HeaderParam(HDR_COMMENT) final String comment,
                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, EntitlementApiException, InvoiceApiException, TagApiException {
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         if (cancelAllSubscriptions) {
@@ -456,8 +455,8 @@ public class AccountResource extends JaxRsResourceBase {
             }
         }
 
-        final BlockingStateJson blockingState = new BlockingStateJson(accountIdStr, "CLOSE_ACCOUNT", "account-service", true, false, false, null, BlockingStateType.ACCOUNT, null);
-        addBlockingState(blockingState, accountIdStr, BlockingStateType.ACCOUNT, null, ImmutableList.<String>of(), createdBy, reason, comment, request);
+        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);
 
         return Response.status(Status.OK).build();
     }
@@ -469,12 +468,11 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account timeline", response = AccountTimelineJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getAccountTimeline(@PathParam("accountId") final String accountIdStr,
+    public Response getAccountTimeline(@PathParam("accountId") final UUID accountId,
                                        @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @QueryParam(QUERY_PARALLEL) @DefaultValue("false") final Boolean parallel,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, SubscriptionApiException, InvoiceApiException, CatalogApiException {
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
@@ -623,11 +621,10 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account email notification", response = InvoiceEmailJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getEmailNotificationsForAccount(@PathParam("accountId") final String accountIdStr,
+    public Response getEmailNotificationsForAccount(@PathParam("accountId") final UUID accountId,
                                                     @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final Account account = accountUserApi.getAccountById(accountId, context.createTenantContextWithAccountId(accountId, request));
-        final InvoiceEmailJson invoiceEmailJson = new InvoiceEmailJson(accountIdStr, account.isNotifiedForInvoices());
+        final InvoiceEmailJson invoiceEmailJson = new InvoiceEmailJson(accountId, account.isNotifiedForInvoices());
 
         return Response.status(Status.OK).entity(invoiceEmailJson).build();
     }
@@ -641,14 +638,12 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response setEmailNotificationsForAccount(final InvoiceEmailJson json,
-                                                    @PathParam("accountId") final String accountIdStr,
+                                                    @PathParam("accountId") final UUID accountId,
                                                     @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 AccountApiException {
         verifyNonNullOrEmpty(json, "InvoiceEmailJson body should be specified");
-
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
@@ -670,15 +665,12 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Rebalance account CBA")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response rebalanceExistingCBAOnAccount(@PathParam("accountId") final String accountIdStr,
+    public Response rebalanceExistingCBAOnAccount(@PathParam("accountId") final UUID accountId,
                                                   @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 AccountApiException {
-
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
-
         invoiceApi.consumeExstingCBAOnAccountWithUnpaidInvoices(accountId, callContext);
         return Response.status(Status.OK).build();
     }
@@ -695,15 +687,13 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account invoices", response = InvoiceJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getInvoices(@PathParam("accountId") final String accountIdStr,
+    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 {
-
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         // Verify the account exists
@@ -735,14 +725,13 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account invoice payments", response = InvoicePaymentJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getInvoicePayments(@PathParam("accountId") final String accountIdStr,
+    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,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
         final List<Payment> payments = paymentApi.getAccountPayments(account.getId(), withPluginInfo, withAttempts, pluginProperties, tenantContext);
@@ -764,7 +753,7 @@ public class AccountResource extends JaxRsResourceBase {
     @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")})
-    public Response payAllInvoices(@PathParam("accountId") final String accountIdStr,
+    public Response payAllInvoices(@PathParam("accountId") final UUID accountId,
                                    @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                    @QueryParam(QUERY_PAYMENT_AMOUNT) final BigDecimal paymentAmount,
                                    @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -774,7 +763,6 @@ public class AccountResource extends JaxRsResourceBase {
                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, InvoiceApiException {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
@@ -819,7 +807,7 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response createPaymentMethod(final PaymentMethodJson json,
-                                        @PathParam("accountId") final String accountIdStr,
+                                        @PathParam("accountId") final UUID accountId,
                                         @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,
@@ -831,13 +819,10 @@ public class AccountResource extends JaxRsResourceBase {
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         verifyNonNullOrEmpty(json, "PaymentMethodJson body should be specified");
         verifyNonNullOrEmpty(json.getPluginName(), "PaymentMethodJson pluginName should be specified");
-
-        final UUID accountId = UUID.fromString(accountIdStr);
-
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
-        final PaymentMethod data = json.toPaymentMethod(accountIdStr);
+        final PaymentMethod data = json.toPaymentMethod(accountId);
         final Account account = accountUserApi.getAccountById(data.getAccountId(), callContext);
 
         final boolean hasDefaultPaymentMethod = account.getPaymentMethodId() != null || isDefault;
@@ -865,14 +850,13 @@ 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 String accountIdStr,
+    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 {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
@@ -895,7 +879,7 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Refresh account payment methods")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response refreshPaymentMethods(@PathParam("accountId") final String accountIdStr,
+    public Response refreshPaymentMethods(@PathParam("accountId") final UUID accountId,
                                           @QueryParam(QUERY_PAYMENT_PLUGIN_NAME) final String pluginName,
                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -903,7 +887,6 @@ public class AccountResource extends JaxRsResourceBase {
                                           @HeaderParam(HDR_COMMENT) final String comment,
                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
@@ -925,8 +908,8 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Set the default payment method")
     @ApiResponses(value = {@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 String accountIdStr,
-                                            @PathParam("paymentMethodId") final String paymentMethodId,
+    public Response setDefaultPaymentMethod(@PathParam("accountId") final UUID accountId,
+                                            @PathParam("paymentMethodId") final UUID paymentMethodId,
                                             @QueryParam(QUERY_PAY_ALL_UNPAID_INVOICES) @DefaultValue("false") final Boolean payAllUnpaidInvoices,
                                             @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -934,17 +917,15 @@ public class AccountResource extends JaxRsResourceBase {
                                             @HeaderParam(HDR_COMMENT) final String comment,
                                             @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
-        final UUID newPaymentMethodId = UUID.fromString(paymentMethodId);
-        paymentApi.setDefaultPaymentMethod(account, newPaymentMethodId, pluginProperties, callContext);
+        paymentApi.setDefaultPaymentMethod(account, paymentMethodId, pluginProperties, callContext);
 
         if (payAllUnpaidInvoices) {
             final Collection<Invoice> unpaidInvoices = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
             for (final Invoice invoice : unpaidInvoices) {
-                createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), newPaymentMethodId, false, null, null, pluginProperties, callContext);
+                createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), paymentMethodId, false, null, null, pluginProperties, callContext);
             }
         }
         return Response.status(Status.OK).build();
@@ -959,13 +940,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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final List<Payment> payments = paymentApi.getAccountPayments(accountId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
@@ -994,8 +974,8 @@ 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,
-                                                @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
-                                                @QueryParam(QUERY_PAYMENT_METHOD_ID) final String paymentMethodIdStr,
+                                                @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,
                                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -1006,7 +986,7 @@ public class AccountResource extends JaxRsResourceBase {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final Account account = accountUserApi.getAccountByKey(externalKey, callContext);
 
-        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
+        return processPayment(json, account, paymentMethodId, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
     }
 
     @TimedResource(name = "processPayment")
@@ -1024,8 +1004,8 @@ 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 processPayment(@MetricTag(tag = "type", property = "transactionType") final PaymentTransactionJson json,
-                                   @PathParam(QUERY_ACCOUNT_ID) final String accountIdStr,
-                                   @QueryParam(QUERY_PAYMENT_METHOD_ID) final String paymentMethodIdStr,
+                                   @PathParam("accountId") final UUID accountId,
+                                   @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,
                                    @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -1033,16 +1013,15 @@ public class AccountResource extends JaxRsResourceBase {
                                    @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 UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         final Account account = accountUserApi.getAccountById(accountId, callContext);
 
-        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
+        return processPayment(json, account, inputPaymentMethodId, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
     }
 
     private Response processPayment(final PaymentTransactionJson json,
                                     final Account account,
-                                    final String paymentMethodIdStr,
+                                    final UUID inputPaymentMethodId,
                                     final List<String> paymentControlPluginNames,
                                     final List<String> pluginPropertiesString,
                                     final UriInfo uriInfo,
@@ -1054,7 +1033,7 @@ public class AccountResource extends JaxRsResourceBase {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
-        final UUID paymentId = json.getPaymentId() == null ? null : UUID.fromString(json.getPaymentId());
+        final UUID paymentId = json.getPaymentId();
 
         //
         // If paymentId was specified, it means we are attempting a payment completion. The preferred way is to use the PaymentResource
@@ -1075,7 +1054,7 @@ public class AccountResource extends JaxRsResourceBase {
 
             paymentMethodId = initialPayment.getPaymentMethodId();
         } else {
-            paymentMethodId = paymentMethodIdStr == null ? account.getPaymentMethodId() : UUID.fromString(paymentMethodIdStr);
+            paymentMethodId = inputPaymentMethodId == null ? account.getPaymentMethodId() : inputPaymentMethodId;
         }
         validatePaymentMethodForAccount(account.getId(), paymentMethodId, callContext);
 
@@ -1115,9 +1094,8 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve overdue state for account", response = OverdueStateJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getOverdueAccount(@PathParam("accountId") final String accountIdStr,
+    public Response getOverdueAccount(@PathParam("accountId") final UUID accountId,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, OverdueException, OverdueApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
 
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
@@ -1137,13 +1115,12 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve blocking states for account", response = BlockingStateJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response getBlockingStates(@PathParam(ID_PARAM_NAME) final String accountIdStr,
+    public Response getBlockingStates(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                       @QueryParam(QUERY_BLOCKING_STATE_TYPES) final List<BlockingStateType> typeFilter,
                                       @QueryParam(QUERY_BLOCKING_STATE_SVCS) final List<String> svcsFilter,
                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException {
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = this.context.createTenantContextWithAccountId(accountId, request);
         final Iterable<BlockingState> blockingStates = subscriptionApi.getBlockingStates(accountId, typeFilter, svcsFilter, OrderingType.ASCENDING, SubscriptionApi.ALL_EVENTS, tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(accountId, auditMode.getLevel(), tenantContext);
@@ -1166,7 +1143,7 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                                           @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,
@@ -1187,10 +1164,9 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve account custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String accountIdStr,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.getCustomFields(accountId, auditMode, context.createTenantContextWithAccountId(accountId, request));
     }
 
@@ -1201,12 +1177,10 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account customFields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getAllCustomFields(@PathParam(ID_PARAM_NAME) final String accountIdString,
+    public Response getAllCustomFields(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                        @QueryParam(QUERY_OBJECT_TYPE) final ObjectType objectType,
                                        @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) {
-        final UUID accountId = UUID.fromString(accountIdString);
-
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final List<CustomField> customFields = objectType != null ?
                                                customFieldUserApi.getCustomFieldsForAccountType(accountId, objectType, tenantContext) :
@@ -1221,14 +1195,13 @@ public class AccountResource extends JaxRsResourceBase {
     @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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.createCustomFields(accountId, customFields, context.createCallContextWithAccountId(accountId, createdBy, reason,
                                                                                                         comment, request), uriInfo, request);
     }
@@ -1241,13 +1214,12 @@ public class AccountResource extends JaxRsResourceBase {
     @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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.modifyCustomFields(accountId, customFields, context.createCallContextWithAccountId(accountId, createdBy, reason,
                                                                                                         comment, request));
     }
@@ -1259,13 +1231,12 @@ public class AccountResource extends JaxRsResourceBase {
     @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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.deleteCustomFields(accountId, customFieldList,
                                         context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
     }
@@ -1281,11 +1252,10 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account tags", response = TagJson.class, responseContainer = "List")
     @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 String accountIdStr,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.getTags(accountId, accountId, auditMode, includedDeleted, context.createTenantContextWithAccountId(accountId, request));
     }
 
@@ -1296,12 +1266,11 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve account tags", response = TagJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response getAllTags(@PathParam(ID_PARAM_NAME) final String accountIdStr,
+    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,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final List<Tag> tags = objectType != null ?
                                tagUserApi.getTagsForAccountType(accountId, objectType, includedDeleted, tenantContext) :
@@ -1315,14 +1284,13 @@ public class AccountResource extends JaxRsResourceBase {
     @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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         return super.createTags(accountId, tagList, uriInfo,
                                 context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request), request);
     }
@@ -1334,13 +1302,12 @@ public class AccountResource extends JaxRsResourceBase {
     @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 String accountIdStr,
+    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 {
-        final UUID accountId = UUID.fromString(accountIdStr);
         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
@@ -1373,14 +1340,13 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve an account emails", response = AccountEmailJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response getEmails(@PathParam(ID_PARAM_NAME) final String accountIdStr,
+    public Response getEmails(@PathParam(ID_PARAM_NAME) final UUID accountId,
                               @javax.ws.rs.core.Context final HttpServletRequest request) {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final List<AccountEmail> emails = accountUserApi.getEmails(accountId, context.createTenantContextWithAccountId(accountId, request));
 
         final List<AccountEmailJson> emailsJson = new ArrayList<AccountEmailJson>();
         for (final AccountEmail email : emails) {
-            emailsJson.add(new AccountEmailJson(email.getAccountId().toString(), email.getEmail()));
+            emailsJson.add(new AccountEmailJson(email.getAccountId(), email.getEmail()));
         }
         return Response.status(Status.OK).entity(emailsJson).build();
     }
@@ -1394,7 +1360,7 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                             @PathParam(ID_PARAM_NAME) final UUID accountId,
                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                              @HeaderParam(HDR_REASON) final String reason,
                              @HeaderParam(HDR_COMMENT) final String comment,
@@ -1402,8 +1368,6 @@ public class AccountResource extends JaxRsResourceBase {
                              @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException {
         verifyNonNullOrEmpty(json, "AccountEmailJson body should be specified");
         verifyNonNullOrEmpty(json.getEmail(), "AccountEmailJson email needs to be set");
-
-        final UUID accountId = UUID.fromString(id);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
 
@@ -1433,18 +1397,16 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Delete email from account")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied")})
-    public Response removeEmail(@PathParam(ID_PARAM_NAME) final String accountIdStr,
+    public Response removeEmail(@PathParam(ID_PARAM_NAME) final UUID accountId,
                                 @PathParam("email") final String email,
                                 @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) {
-        final UUID accountId = UUID.fromString(accountIdStr);
-
         final List<AccountEmail> emails = accountUserApi.getEmails(accountId, context.createTenantContextWithAccountId(accountId, request));
         for (final AccountEmail cur : emails) {
             if (cur.getEmail().equals(email)) {
-                final AccountEmailJson accountEmailJson = new AccountEmailJson(accountId.toString(), email);
+                final AccountEmailJson accountEmailJson = new AccountEmailJson(accountId, email);
                 final AccountEmail accountEmail = accountEmailJson.toAccountEmail(cur.getId());
                 accountUserApi.removeEmail(accountId, accountEmail, context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request));
             }
@@ -1468,13 +1430,12 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "List children accounts", response = AccountJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid parent account id supplied"),
                            @ApiResponse(code = 404, message = "Parent Account not found")})
-    public Response getChildrenAccounts(@PathParam("accountId") final String parentAccountIdStr,
+    public Response getChildrenAccounts(@PathParam("accountId") final UUID parentAccountId,
                                         @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,
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
 
-        final UUID parentAccountId = UUID.fromString(parentAccountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(parentAccountId, request);
         final List<Account> accounts = accountUserApi.getChildrenAccounts(parentAccountId, tenantContext);
 
@@ -1494,14 +1455,13 @@ public class AccountResource extends JaxRsResourceBase {
     @ApiOperation(value = "Move a given child credit to the parent level")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Account does not have credit"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response transferChildCreditToParent(@PathParam("childAccountId") final String childAccountIdStr,
+    public Response transferChildCreditToParent(@PathParam("childAccountId") final UUID childAccountId,
                                                 @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 InvoiceApiException {
 
-        final UUID childAccountId = UUID.fromString(childAccountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(childAccountId, createdBy, reason, comment, request);
 
         invoiceApi.transferChildCreditToParent(childAccountId, callContext);
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 f439655..443cba2 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
@@ -105,7 +105,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.ADMIN_PATH)
-@Api(value = JaxrsResource.ADMIN_PATH, description = "Admin operations (will require special privileges)")
+@Api(value = JaxrsResource.ADMIN_PATH, description = "Admin operations (will require special privileges)", tags="Admin")
 public class AdminResource extends JaxRsResourceBase {
 
     private static final String OK = "OK";
@@ -150,9 +150,9 @@ public class AdminResource extends JaxRsResourceBase {
     @GET
     @Path("/queues")
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Get queues entries", response = Response.class)
+    @ApiOperation(value = "Get queues entries", response = Response.class, hidden=true)
     @ApiResponses(value = {})
-    public Response getQueueEntries(@QueryParam("accountId") final String accountIdStr,
+    public Response getQueueEntries(@QueryParam("accountId") final UUID accountId,
                                     @QueryParam("queueName") final String queueName,
                                     @QueryParam("serviceName") final String serviceName,
                                     @QueryParam("withHistory") @DefaultValue("true") final Boolean withHistory,
@@ -164,7 +164,7 @@ public class AdminResource extends JaxRsResourceBase {
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Long tenantRecordId = recordIdApi.getRecordId(tenantContext.getTenantId(), ObjectType.TENANT, tenantContext);
-        final Long accountRecordId = Strings.isNullOrEmpty(accountIdStr) ? null : recordIdApi.getRecordId(UUID.fromString(accountIdStr), ObjectType.ACCOUNT, tenantContext);
+        final Long accountRecordId = accountId == null ? null : recordIdApi.getRecordId(accountId, ObjectType.ACCOUNT, tenantContext);
 
         // Limit search results by default
         final DateTime minDate = Strings.isNullOrEmpty(minDateOrNull) ? clock.getUTCNow().minusDays(2) : DATE_TIME_FORMATTER.parseDateTime(minDateOrNull).toDateTime(DateTimeZone.UTC);
@@ -233,8 +233,8 @@ public class AdminResource extends JaxRsResourceBase {
     @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 String paymentIdStr,
-                                                  @PathParam("paymentTransactionId") final String paymentTransactionIdStr,
+                                                  @PathParam("paymentId") final UUID paymentId,
+                                                  @PathParam("paymentTransactionId") final UUID paymentTransactionId,
                                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                   @HeaderParam(HDR_REASON) final String reason,
                                                   @HeaderParam(HDR_COMMENT) final String comment,
@@ -242,10 +242,7 @@ public class AdminResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Payment payment = paymentApi.getPayment(UUID.fromString(paymentIdStr), false, false, ImmutableList.<PluginProperty>of(), callContext);
-
-        final UUID paymentTransactionId = UUID.fromString(paymentTransactionIdStr);
-
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
         final PaymentTransaction paymentTransaction = Iterables.tryFind(payment.getTransactions(), new Predicate<PaymentTransaction>() {
             @Override
             public boolean apply(final PaymentTransaction input) {
@@ -349,16 +346,15 @@ public class AdminResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Invalidates Caches per account level")
     @ApiResponses(value = {})
-    public Response invalidatesCacheByAccount(@PathParam("accountId") final String accountIdStr,
+    public Response invalidatesCacheByAccount(@PathParam("accountId") final UUID accountId,
                                               @javax.ws.rs.core.Context final HttpServletRequest request) {
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final Long accountRecordId = recordIdApi.getRecordId(accountId, ObjectType.ACCOUNT, tenantContext);
 
         // clear account-record-id cache by accountId (note: String!)
         final CacheController<String, Long> accountRecordIdCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID);
-        accountRecordIdCacheController.remove(accountIdStr);
+        accountRecordIdCacheController.remove(accountId.toString());
 
         // clear account-immutable cache by account record id
         final CacheController<Long, ImmutableAccountData> accountImmutableCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
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 cff17bc..476d72a 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
@@ -80,13 +80,14 @@ import com.google.common.collect.ImmutableMap;
 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.BUNDLES_PATH)
-@Api(value = JaxrsResource.BUNDLES_PATH, description = "Operations on bundles")
+@Api(value = JaxrsResource.BUNDLES_PATH, description = "Operations on bundles", tags="Bundle")
 public class BundleResource extends JaxRsResourceBase {
 
     private static final String ID_PARAM_NAME = "bundleId";
@@ -117,12 +118,11 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a bundle by id", response = BundleJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response getBundle(@PathParam("bundleId") final String bundleId,
+    public Response getBundle(@PathParam("bundleId") final UUID bundleId,
                               @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, CatalogApiException {
-        final UUID id = UUID.fromString(bundleId);
         final TenantContext tenantContext = this.context.createTenantContextNoAccountId(request);
-        final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(id, tenantContext);
+        final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, tenantContext);
         final Account account = accountUserApi.getAccountById(bundle.getAccountId(), tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(bundle.getAccountId(), auditMode.getLevel(), tenantContext);
         final BundleJson json = new BundleJson(bundle, account.getCurrency(), accountAuditLogs);
@@ -134,7 +134,7 @@ public class BundleResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve a bundle by external key", response = BundleJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Bundle not found")})
-    public Response getBundleByKey(@QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+    public Response getBundleByKey(@ApiParam(required=true) @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
                                    @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 SubscriptionApiException, AccountApiException, CatalogApiException {
@@ -235,7 +235,7 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiOperation(value = "Pause a bundle")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response pauseBundle(@PathParam(ID_PARAM_NAME) final String id,
+    public Response pauseBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                 @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -244,7 +244,6 @@ public class BundleResource extends JaxRsResourceBase {
                                 @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID bundleId = UUID.fromString(id);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
         entitlementApi.pause(bundleId, inputLocalDate, pluginProperties, callContext);
         return Response.status(Status.OK).build();
@@ -258,7 +257,7 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiOperation(value = "Resume a bundle")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied"),
                            @ApiResponse(code = 404, message = "Bundle not found")})
-    public Response resumeBundle(@PathParam(ID_PARAM_NAME) final String id,
+    public Response resumeBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                  @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                  @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                  @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -267,7 +266,6 @@ public class BundleResource extends JaxRsResourceBase {
                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, EntitlementApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID bundleId = UUID.fromString(id);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
         entitlementApi.resume(bundleId, inputLocalDate, pluginProperties, callContext);
         return Response.status(Status.OK).build();
@@ -281,7 +279,7 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                                           @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,
@@ -299,10 +297,10 @@ public class BundleResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve bundle custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid bundle id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID bundleId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(bundleId, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -312,14 +310,14 @@ public class BundleResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(bundleId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -330,13 +328,13 @@ public class BundleResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(bundleId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -350,13 +348,13 @@ public class BundleResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(bundleId, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -367,11 +365,10 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve bundle tags", response = TagJson.class, responseContainer = "List")
     @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 String bundleIdString,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
-        final UUID bundleId = UUID.fromString(bundleIdString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, tenantContext);
         return super.getTags(bundle.getAccountId(), bundleId, auditMode, includedDeleted, tenantContext);
@@ -386,7 +383,7 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                                   @PathParam(ID_PARAM_NAME) final UUID bundleId,
                                    @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
                                    @QueryParam(QUERY_BILLING_POLICY) @DefaultValue("END_OF_TERM") final String policyString,
                                    @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -402,12 +399,10 @@ public class BundleResource extends JaxRsResourceBase {
         final BillingActionPolicy policy = BillingActionPolicy.valueOf(policyString.toUpperCase());
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID bundleId = UUID.fromString(id);
-
         final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, callContext);
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
 
-        final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), UUID.fromString(json.getAccountId()), bundle.getExternalKey(), inputLocalDate, policy, pluginProperties, callContext);
+        final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), json.getAccountId(), bundle.getExternalKey(), inputLocalDate, policy, pluginProperties, callContext);
         return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", newBundleId, request);
     }
 
@@ -420,7 +415,7 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                                      @PathParam(ID_PARAM_NAME) final UUID bundleId,
                                       /* @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, */
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
@@ -431,8 +426,6 @@ public class BundleResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json, "BundleJson body should be specified");
         verifyNonNullOrEmpty(json.getExternalKey(), "BundleJson externalKey needs to be set");
 
-        final UUID bundleId = UUID.fromString(id);
-
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         subscriptionApi.updateExternalKey(bundleId, json.getExternalKey(), callContext);
         return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", bundleId, request);
@@ -447,14 +440,14 @@ public class BundleResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(bundleId, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -465,13 +458,13 @@ public class BundleResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        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 c68ce54..70752e0 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
@@ -91,7 +91,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_XML;
 
 @Singleton
 @Path(JaxrsResource.CATALOG_PATH)
-@Api(value = JaxrsResource.CATALOG_PATH, description = "Catalog information")
+@Api(value = JaxrsResource.CATALOG_PATH, description = "Catalog information", tags="Catalog")
 public class CatalogResource extends JaxRsResourceBase {
 
     private final CatalogUserApi catalogUserApi;
@@ -222,12 +222,12 @@ public class CatalogResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve plan for a given subscription and date", response = PlanJson.class)
     @ApiResponses(value = {})
-    public Response getPlanForSubscriptionAndDate(@QueryParam("subscriptionId") final String subscriptionIdString,
+    public Response getPlanForSubscriptionAndDate(@QueryParam("subscriptionId") final UUID subscriptionId,
                                                   @QueryParam("requestedDate") final String requestedDateString,
                                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, CurrencyValueNull {
-        verifyNonNullOrEmpty(subscriptionIdString, "Subscription id needs to be specified");
+        verifyNonNullOrEmpty(subscriptionId, "Subscription id needs to be specified");
 
-        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionIdString, requestedDateString, request);
+        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionId, requestedDateString, request);
         if (lastEventBeforeRequestedDate == null) {
             return Response.status(Status.BAD_REQUEST).entity(String.format("%s is before the subscription start date", requestedDateString)).type("text/plain").build();
         }
@@ -248,12 +248,12 @@ public class CatalogResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve phase for a given subscription and date", response = PhaseJson.class)
     @ApiResponses(value = {})
-    public Response getPhaseForSubscriptionAndDate(@QueryParam("subscriptionId") final String subscriptionIdString,
+    public Response getPhaseForSubscriptionAndDate(@QueryParam("subscriptionId") final UUID subscriptionId,
                                                    @QueryParam("requestedDate") final String requestedDateString,
                                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, CurrencyValueNull {
-        verifyNonNullOrEmpty(subscriptionIdString, "Subscription id needs to be specified");
+        verifyNonNullOrEmpty(subscriptionId, "Subscription id needs to be specified");
 
-        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionIdString, requestedDateString, request);
+        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionId, requestedDateString, request);
         if (lastEventBeforeRequestedDate == null) {
             return Response.status(Status.BAD_REQUEST).entity(String.format("%s is before the subscription start date", requestedDateString)).type("text/plain").build();
         }
@@ -274,12 +274,12 @@ public class CatalogResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve product for a given subscription and date", response = ProductJson.class)
     @ApiResponses(value = {})
-    public Response getProductForSubscriptionAndDate(@QueryParam("subscriptionId") final String subscriptionIdString,
+    public Response getProductForSubscriptionAndDate(@QueryParam("subscriptionId") final UUID subscriptionId,
                                                      @QueryParam("requestedDate") final String requestedDateString,
                                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException {
-        verifyNonNullOrEmpty(subscriptionIdString, "Subscription id needs to be specified");
+        verifyNonNullOrEmpty(subscriptionId, "Subscription id needs to be specified");
 
-        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionIdString, requestedDateString, request);
+        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionId, requestedDateString, request);
         if (lastEventBeforeRequestedDate == null) {
             return Response.status(Status.BAD_REQUEST).entity(String.format("%s is before the subscription start date", requestedDateString)).type("text/plain").build();
         }
@@ -300,12 +300,12 @@ public class CatalogResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve priceList for a given subscription and date", response = PriceListJson.class)
     @ApiResponses(value = {})
-    public Response getPriceListForSubscriptionAndDate(@QueryParam("subscriptionId") final String subscriptionIdString,
+    public Response getPriceListForSubscriptionAndDate(@QueryParam("subscriptionId") final UUID subscriptionId,
                                                        @QueryParam("requestedDate") final String requestedDateString,
                                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException {
-        verifyNonNullOrEmpty(subscriptionIdString, "Subscription id needs to be specified");
+        verifyNonNullOrEmpty(subscriptionId, "Subscription id needs to be specified");
 
-        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionIdString, requestedDateString, request);
+        final SubscriptionEvent lastEventBeforeRequestedDate = getLastEventBeforeDate(subscriptionId, requestedDateString, request);
         if (lastEventBeforeRequestedDate == null) {
             return Response.status(Status.BAD_REQUEST).entity(String.format("%s is before the subscription start date", requestedDateString)).type("text/plain").build();
         }
@@ -320,14 +320,14 @@ public class CatalogResource extends JaxRsResourceBase {
         return Response.status(Status.OK).entity(priceListJson).build();
     }
 
-    private SubscriptionEvent getLastEventBeforeDate(final String subscriptionIdString, final String requestedDateString, final HttpServletRequest request) throws SubscriptionApiException {
+    private SubscriptionEvent getLastEventBeforeDate(final UUID subscriptionId, final String requestedDateString, final HttpServletRequest request) throws SubscriptionApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final DateTime requestedDateTime = requestedDateString != null ?
                                            DATE_TIME_FORMATTER.parseDateTime(requestedDateString).toDateTime(DateTimeZone.UTC) :
                                            clock.getUTCNow();
         final LocalDate requestedDate = requestedDateTime.toLocalDate();
 
-        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(UUID.fromString(subscriptionIdString), tenantContext);
+        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(subscriptionId, tenantContext);
         SubscriptionEvent lastEventBeforeRequestedDate = null;
         for (final SubscriptionEvent subscriptionEvent : subscription.getSubscriptionEvents()) {
             if (lastEventBeforeRequestedDate == null) {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
index bc87d1e..f93fd74 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
@@ -65,7 +65,7 @@ public abstract class ComboPaymentResource extends JaxRsResourceBase {
     protected Account getOrCreateAccount(final AccountJson accountJson, final CallContext callContext) throws AccountApiException {
         // Attempt to retrieve by accountId if specified
         if (accountJson.getAccountId() != null) {
-            return accountUserApi.getAccountById(UUID.fromString(accountJson.getAccountId()), callContext);
+            return accountUserApi.getAccountById(accountJson.getAccountId(), callContext);
         }
 
         if (accountJson.getExternalKey() != null) {
@@ -91,7 +91,7 @@ public abstract class ComboPaymentResource extends JaxRsResourceBase {
 
         // If we were specified a paymentMethod id and we find it, we return it
         if (paymentMethodJson.getPaymentMethodId() != null) {
-            final UUID match = UUID.fromString(paymentMethodJson.getPaymentMethodId());
+            final UUID match = paymentMethodJson.getPaymentMethodId();
             if (Iterables.any(accountPaymentMethods, new Predicate<PaymentMethod>() {
                 @Override
                 public boolean apply(final PaymentMethod input) {
@@ -118,7 +118,7 @@ public abstract class ComboPaymentResource extends JaxRsResourceBase {
 
         // Only set as default if this is the first paymentMethod on the account
         final boolean isDefault = accountPaymentMethods.isEmpty();
-        final PaymentMethod paymentData = paymentMethodJson.toPaymentMethod(account.getId().toString());
+        final PaymentMethod paymentData = paymentMethodJson.toPaymentMethod(account.getId());
         return paymentApi.addPaymentMethod(account, paymentMethodJson.getExternalKey(), paymentMethodJson.getPluginName(), isDefault,
                                            paymentData.getPluginDetail(), pluginProperties, callContext);
     }
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 f816d4e..d560165 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
@@ -62,7 +62,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.CREDITS_PATH)
-@Api(value = JaxrsResource.CREDITS_PATH, description = "Operations on credits")
+@Api(value = JaxrsResource.CREDITS_PATH, description = "Operations on credits", tags="Credit")
 public class CreditResource extends JaxRsResourceBase {
 
     private final InvoiceUserApi invoiceUserApi;
@@ -89,10 +89,10 @@ public class CreditResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a credit by id", response = CreditJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid credit id supplied"),
                            @ApiResponse(code = 404, message = "Credit not found")})
-    public Response getCredit(@PathParam("creditId") final String creditId,
+    public Response getCredit(@PathParam("creditId") final UUID creditId,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, AccountApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final InvoiceItem credit = invoiceUserApi.getCreditById(UUID.fromString(creditId), tenantContext);
+        final InvoiceItem credit = invoiceUserApi.getCreditById(creditId, tenantContext);
         final Invoice invoice = invoiceUserApi.getInvoice(credit.getInvoiceId(), tenantContext);
         final CreditJson creditJson = new CreditJson(invoice, credit);
         return Response.status(Response.Status.OK).entity(creditJson).build();
@@ -117,13 +117,13 @@ public class CreditResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Account account = accountUserApi.getAccountById(UUID.fromString(json.getAccountId()), callContext);
+        final Account account = accountUserApi.getAccountById(json.getAccountId(), callContext);
         final LocalDate effectiveDate = new LocalDate(clock.getUTCNow(), account.getTimeZone());
 
         final InvoiceItem credit;
         if (json.getInvoiceId() != null) {
             // Apply an invoice level credit
-            credit = invoiceUserApi.insertCreditForInvoice(account.getId(), UUID.fromString(json.getInvoiceId()), json.getCreditAmount(),
+            credit = invoiceUserApi.insertCreditForInvoice(account.getId(), json.getInvoiceId(), json.getCreditAmount(),
                                                            effectiveDate, account.getCurrency(), json.getDescription(), callContext);
         } else {
             // Apply a account level credit
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CustomFieldResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CustomFieldResource.java
index 6088379..69fcd94 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CustomFieldResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CustomFieldResource.java
@@ -57,7 +57,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.CUSTOM_FIELDS_PATH)
-@Api(value = JaxrsResource.CUSTOM_FIELDS_PATH, description = "Operations on custom fields")
+@Api(value = JaxrsResource.CUSTOM_FIELDS_PATH, description = "Operations on custom fields", tags="CustomField")
 public class CustomFieldResource extends JaxRsResourceBase {
 
     @Inject
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 ea4be80..aeccced 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
@@ -52,7 +52,7 @@ import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
 
 @Singleton
 @Path(JaxrsResource.EXPORT_PATH)
-@Api(value = JaxrsResource.EXPORT_PATH, description = "Export endpoints")
+@Api(value = JaxrsResource.EXPORT_PATH, description = "Export endpoints", tags="Export")
 public class ExportResource extends JaxRsResourceBase {
 
     private final ExportUserApi exportUserApi;
@@ -78,13 +78,11 @@ public class ExportResource extends JaxRsResourceBase {
     @ApiOperation(value = "Export account data", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public StreamingOutput exportDataForAccount(@PathParam("accountId") final String accountIdStr
-            ,
+    public StreamingOutput exportDataForAccount(@PathParam("accountId") final UUID accountId,
                                                 @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) {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         return new StreamingOutput() {
             @Override
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 7235277..3b94ad5 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
@@ -58,13 +58,14 @@ import org.killbill.commons.metrics.TimedResource;
 
 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.INVOICES_ITEMS_PATH)
-@Api(value = JaxrsResource.INVOICES_ITEMS_PATH, description = "Operations on invoice items")
+@Api(value = JaxrsResource.INVOICES_ITEMS_PATH, description = "Operations on invoice items", tags="InvoiceItem")
 public class InvoiceItemResource extends JaxRsResourceBase {
     private static final String ID_PARAM_NAME = "invoiceItemId";
 
@@ -81,10 +82,10 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve invoice item custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice item id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -94,14 +95,14 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -113,13 +114,13 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -131,13 +132,13 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -148,16 +149,15 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve invoice item tags", response = TagJson.class, responseContainer = "List")
     @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 String id,
-                            @QueryParam(QUERY_ACCOUNT_ID) final String accountIdStr,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, AccountApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final TenantContext tenantContext = context.createTenantContextWithAccountId(accountId, request);
         final Account account = accountUserApi.getAccountById(accountId, tenantContext);
 
-        return super.getTags(account.getId(), UUID.fromString(id), auditMode, includedDeleted, tenantContext);
+        return super.getTags(account.getId(), id, auditMode, includedDeleted, tenantContext);
     }
 
     @TimedResource
@@ -167,14 +167,14 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -185,13 +185,13 @@ public class InvoiceItemResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        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 a98cea9..c75b4e5 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
@@ -88,7 +88,7 @@ import io.swagger.annotations.ApiResponses;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Path(JaxrsResource.INVOICE_PAYMENTS_PATH)
-@Api(value = JaxrsResource.INVOICE_PAYMENTS_PATH, description = "Operations on invoice payments")
+@Api(value = JaxrsResource.INVOICE_PAYMENTS_PATH, description = "Operations on invoice payments", tags="InvoicePayment")
 public class InvoicePaymentResource extends JaxRsResourceBase {
 
     private static final String ID_PARAM_NAME = "paymentId";
@@ -116,7 +116,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a payment by id", response = InvoicePaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied"),
                            @ApiResponse(code = 404, message = "Payment not found")})
-    public Response getInvoicePayment(@PathParam("paymentId") final String paymentIdStr,
+    public Response getInvoicePayment(@PathParam("paymentId") final UUID paymentId,
                                       @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,
@@ -124,12 +124,11 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID paymentIdId = UUID.fromString(paymentIdStr);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Payment payment = paymentApi.getPayment(paymentIdId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
+        final Payment payment = paymentApi.getPayment(paymentId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(payment.getAccountId(), auditMode.getLevel(), tenantContext);
 
-        final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePayments(paymentIdId, tenantContext);
+        final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePayments(paymentId, tenantContext);
         final InvoicePayment invoicePayment = Iterables.tryFind(invoicePayments, new Predicate<InvoicePayment>() {
             @Override
             public boolean apply(final InvoicePayment input) {
@@ -151,9 +150,9 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String paymentId,
+                                                @PathParam("paymentId") final UUID paymentId,
                                                 @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
-                                                @QueryParam(QUERY_PAYMENT_METHOD_ID) @DefaultValue("") final String paymentMethodId,
+                                                @QueryParam(QUERY_PAYMENT_METHOD_ID) final UUID paymentMethodId,
                                                 @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                                 @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                 @HeaderParam(HDR_REASON) final String reason,
@@ -163,8 +162,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json, "InvoicePaymentTransactionJson body should be specified");
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID paymentUuid = UUID.fromString(paymentId);
-        final Payment payment = paymentApi.getPayment(paymentUuid, false, false, ImmutableList.<PluginProperty>of(), callContext);
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
         final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
 
         final Iterable<PluginProperty> pluginProperties;
@@ -174,7 +172,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
             if (json.getAdjustments() != null && json.getAdjustments().size() > 0) {
                 final Map<UUID, BigDecimal> adjustments = new HashMap<UUID, BigDecimal>();
                 for (final InvoiceItemJson item : json.getAdjustments()) {
-                    adjustments.put(UUID.fromString(item.getInvoiceItemId()), item.getAmount());
+                    adjustments.put(item.getInvoiceItemId(), item.getAmount());
                 }
                 pluginProperties = extractPluginProperties(pluginPropertiesString,
                                                            new PluginProperty("IPCD_REFUND_WITH_ADJUSTMENTS", "true", false),
@@ -189,11 +187,11 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
 
         final Payment result;
         if (externalPayment) {
-            UUID externalPaymentMethodId = Strings.isNullOrEmpty(paymentMethodId) ? null : UUID.fromString(paymentMethodId);
+            UUID externalPaymentMethodId = paymentMethodId;
 
             final Collection<PluginProperty> pluginPropertiesForExternalRefund = new LinkedList<PluginProperty>();
             Iterables.addAll(pluginPropertiesForExternalRefund, pluginProperties);
-            pluginPropertiesForExternalRefund.add(new PluginProperty("IPCD_PAYMENT_ID", paymentUuid, false));
+            pluginPropertiesForExternalRefund.add(new PluginProperty("IPCD_PAYMENT_ID", paymentId, false));
 
             result = paymentApi.createCreditWithPaymentControl(account, externalPaymentMethodId, null, json.getAmount(), account.getCurrency(), json.getEffectiveDate(),
                                                                paymentExternalKey, transactionExternalKey, pluginPropertiesForExternalRefund,
@@ -215,7 +213,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String paymentId,
+                                     @PathParam("paymentId") final UUID paymentId,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
                                      @HeaderParam(HDR_COMMENT) final String comment,
@@ -225,8 +223,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json.getAmount(), "InvoicePaymentTransactionJson amount needs to be set");
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID paymentUuid = UUID.fromString(paymentId);
-        final Payment payment = paymentApi.getPayment(paymentUuid, false, false, ImmutableList.<PluginProperty>of(), callContext);
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
         final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
         final String transactionExternalKey = json.getTransactionExternalKey() != null ? json.getTransactionExternalKey() : UUIDs.randomUUID().toString();
 
@@ -244,18 +241,17 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String paymentId,
+                                             @PathParam("paymentId") final UUID paymentId,
                                              @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 {
         verifyNonNullOrEmpty(json, "InvoicePaymentTransactionJson body should be specified");
-        verifyNonNullOrEmpty(json.getTransactionExternalKey(), "transactionExternalKey amount needs to be set");
+        verifyNonNullOrEmpty(json.getTransactionExternalKey(), "InvoicePaymentTransactionJson transactionExternalKey needs to be set");
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID paymentUuid = UUID.fromString(paymentId);
-        final Payment payment = paymentApi.getPayment(paymentUuid, false, false, ImmutableList.<PluginProperty>of(), callContext);
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
         final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
 
         final Payment result = paymentApi.createChargebackReversalWithPaymentControl(account, payment.getId(), json.getEffectiveDate(), json.getTransactionExternalKey(), createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
@@ -278,7 +274,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                            @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 String paymentIdStr,
+                                        @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,
@@ -288,9 +284,6 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
 
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-
-        final UUID paymentId = UUID.fromString(paymentIdStr);
-
         final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
         final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePayments(paymentId, tenantContext);
 
@@ -324,10 +317,10 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -337,14 +330,14 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -356,13 +349,13 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -374,13 +367,13 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -391,13 +384,12 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve payment tags", response = TagJson.class, responseContainer = "List")
     @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 String paymentIdString,
+    public Response getTags(@PathParam(ID_PARAM_NAME) final UUID paymentId,
                             @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 UUID paymentId = UUID.fromString(paymentIdString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Payment payment = paymentApi.getPayment(paymentId, false, false, pluginProperties, tenantContext);
         return super.getTags(payment.getAccountId(), paymentId, auditMode, includedDeleted, tenantContext);
@@ -410,14 +402,14 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -428,13 +420,13 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        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 df9215f..8855d34 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
@@ -119,6 +119,7 @@ import com.google.common.collect.Ordering;
 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;
 
@@ -127,7 +128,7 @@ import static javax.ws.rs.core.MediaType.TEXT_HTML;
 import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
 
 @Path(JaxrsResource.INVOICES_PATH)
-@Api(value = JaxrsResource.INVOICES_PATH, description = "Operations on invoices")
+@Api(value = JaxrsResource.INVOICES_PATH, description = "Operations on invoices", tags="Invoice")
 public class InvoiceResource extends JaxRsResourceBase {
 
     private static final Logger log = LoggerFactory.getLogger(InvoiceResource.class);
@@ -169,13 +170,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve an invoice by id", response = InvoiceJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
-    public Response getInvoice(@PathParam("invoiceId") final String invoiceId,
+    public Response getInvoice(@PathParam("invoiceId") final UUID invoiceId,
                                @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
                                @QueryParam(QUERY_INVOICE_WITH_CHILDREN_ITEMS) @DefaultValue("false") final boolean withChildrenItems,
                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);
+        final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
         final List<InvoiceItem> childInvoiceItems = withChildrenItems ? invoiceApi.getInvoiceItemsByParentInvoice(invoice.getId(), tenantContext) : null;
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(invoice.getAccountId(), auditMode.getLevel(), tenantContext);
 
@@ -217,9 +218,9 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(TEXT_HTML)
     @ApiOperation(value = "Render an invoice as HTML", response = String.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
-    public Response getInvoiceAsHTML(@PathParam("invoiceId") final String invoiceId,
+    public Response getInvoiceAsHTML(@PathParam("invoiceId") final UUID invoiceId,
                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, IOException, AccountApiException {
-        return Response.status(Status.OK).entity(invoiceApi.getInvoiceAsHTML(UUID.fromString(invoiceId), context.createTenantContextNoAccountId(request))).build();
+        return Response.status(Status.OK).entity(invoiceApi.getInvoiceAsHTML(invoiceId, context.createTenantContextNoAccountId(request))).build();
     }
 
     @TimedResource
@@ -293,7 +294,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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")})
-    public Response createFutureInvoice(@QueryParam(QUERY_ACCOUNT_ID) final String accountIdStr,
+    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,
                                         @HeaderParam(HDR_REASON) final String reason,
@@ -301,7 +302,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                                         @javax.ws.rs.core.Context final HttpServletRequest request,
                                         @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
 
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         final LocalDate inputDate = toLocalDate(targetDate);
 
@@ -322,17 +322,16 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path("/" + MIGRATION + "/{accountId:" + UUID_PATTERN + "}")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create a migration invoice", response = InvoiceJson.class)
+    @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 Iterable<InvoiceItemJson> items,
-                                           @PathParam("accountId") final String accountIdStr,
+    public Response createMigrationInvoice(final List<InvoiceItemJson> items,
+                                           @PathParam("accountId") final UUID accountId,
                                            @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                            @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 AccountApiException, InvoiceApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
@@ -350,14 +349,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Generate a dryRun invoice", response = InvoiceJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
     public Response generateDryRunInvoice(@Nullable final InvoiceDryRunJson dryRunSubscriptionSpec,
-                                          @QueryParam(QUERY_ACCOUNT_ID) final String accountIdStr,
+                                          @ApiParam(required=true) @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
                                           @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                           @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 AccountApiException, InvoiceApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         final LocalDate inputDate;
         if (dryRunSubscriptionSpec != null) {
@@ -414,19 +412,18 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Delete a CBA item")
     @ApiResponses(value = {@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 String invoiceId,
-                              @PathParam("invoiceItemId") final String invoiceItemId,
-                              @QueryParam(QUERY_ACCOUNT_ID) final String accountIdStr,
+    public Response deleteCBA(@PathParam("invoiceId") final UUID invoiceId,
+                              @PathParam("invoiceItemId") final UUID invoiceItemId,
+                              @ApiParam(required=true) @QueryParam(QUERY_ACCOUNT_ID) final UUID accountId,
                               @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 AccountApiException, InvoiceApiException {
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
 
-        invoiceApi.deleteCBA(account.getId(), UUID.fromString(invoiceId), UUID.fromString(invoiceItemId), callContext);
+        invoiceApi.deleteCBA(account.getId(), invoiceId, invoiceItemId, callContext);
 
         return Response.status(Status.OK).build();
     }
@@ -440,7 +437,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String invoiceId,
+                                      @PathParam("invoiceId") final UUID invoiceId,
                                       @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
@@ -451,22 +448,22 @@ public class InvoiceResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json.getAccountId(), "InvoiceItemJson accountId needs to be set",
                              json.getInvoiceItemId(), "InvoiceItemJson invoiceItemId needs to be set");
 
-        final UUID accountId = UUID.fromString(json.getAccountId());
+        final UUID accountId = json.getAccountId();
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final LocalDate requestedDate = toLocalDateDefaultToday(accountId, requestedDateTimeString, callContext);
         final InvoiceItem adjustmentItem;
         if (json.getAmount() == null) {
             adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId,
-                                                                    UUID.fromString(invoiceId),
-                                                                    UUID.fromString(json.getInvoiceItemId()),
+                                                                    invoiceId,
+                                                                    json.getInvoiceItemId(),
                                                                     requestedDate,
                                                                     json.getDescription(),
                                                                     callContext);
         } else {
             adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId,
-                                                                    UUID.fromString(invoiceId),
-                                                                    UUID.fromString(json.getInvoiceItemId()),
+                                                                    invoiceId,
+                                                                    json.getInvoiceItemId(),
                                                                     requestedDate,
                                                                     json.getAmount(),
                                                                     Currency.valueOf(json.getCurrency()),
@@ -489,8 +486,8 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Create external charge(s)", response = InvoiceItemJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
-    public Response createExternalCharges(final Iterable<InvoiceItemJson> externalChargesJson,
-                                          @PathParam("accountId") final String accountIdStr,
+    public Response createExternalCharges(final List<InvoiceItemJson> externalChargesJson,
+                                          @PathParam("accountId") final UUID accountId,
                                           @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                           @QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
                                           @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -504,7 +501,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                                           @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException, PaymentApiException {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID accountId = UUID.fromString(accountIdStr);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
@@ -604,14 +600,14 @@ 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 String invoiceId,
+    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 {
 
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);
+        final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
 
         // Extract unique set of paymentId for this invoice
         final Set<UUID> invoicePaymentIds = ImmutableSet.copyOf(Iterables.transform(invoice.getPayments(), new Function<InvoicePayment, UUID>() {
@@ -648,7 +644,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String invoiceId,
+                                         @PathParam("invoiceId") final UUID invoiceId,
                                          @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -665,11 +661,11 @@ public class InvoiceResource extends JaxRsResourceBase {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Account account = accountUserApi.getAccountById(UUID.fromString(payment.getAccountId()), callContext);
+        final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
         final UUID paymentMethodId = externalPayment ? null :
-                                     (payment.getPaymentMethodId() != null ? UUID.fromString(payment.getPaymentMethodId()) : account.getPaymentMethodId());
+                                     (payment.getPaymentMethodId() != null ? payment.getPaymentMethodId() : account.getPaymentMethodId());
 
-        final Payment result = createPurchaseForInvoice(account, UUID.fromString(invoiceId), payment.getPurchasedAmount(), paymentMethodId, externalPayment,
+        final Payment result = createPurchaseForInvoice(account, invoiceId, payment.getPurchasedAmount(), paymentMethodId, externalPayment,
                                                         payment.getPaymentExternalKey(), null, pluginProperties, callContext);
         return result != null ?
                uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request) :
@@ -879,10 +875,10 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve invoice custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -892,14 +888,14 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -911,13 +907,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -928,13 +924,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -945,11 +941,10 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve invoice tags", response = TagJson.class, responseContainer = "List")
     @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 String invoiceIdString,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, InvoiceApiException {
-        final UUID invoiceId = UUID.fromString(invoiceIdString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
         return super.getTags(invoice.getAccountId(), invoiceId, auditMode, includedDeleted, tenantContext);
@@ -962,14 +957,14 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -980,13 +975,13 @@ public class InvoiceResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -997,7 +992,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Perform the invoice status transition from DRAFT to COMMITTED")
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
-    public Response commitInvoice(@PathParam("invoiceId") final String invoiceIdString,
+    public Response commitInvoice(@PathParam("invoiceId") final UUID invoiceId,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
                                   @HeaderParam(HDR_COMMENT) final String comment,
@@ -1005,7 +1000,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws InvoiceApiException {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID invoiceId = UUID.fromString(invoiceIdString);
         invoiceApi.commitInvoice(invoiceId, callContext);
         return Response.status(Response.Status.OK).build();
     }
@@ -1018,7 +1012,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @ApiOperation(value = "Perform the action of voiding an invoice")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                            @ApiResponse(code = 404, message = "Invoice not found")})
-    public Response voidInvoice(@PathParam("invoiceId") final String invoiceIdString,
+    public Response voidInvoice(@PathParam("invoiceId") final UUID invoiceId,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
                                   @HeaderParam(HDR_COMMENT) final String comment,
@@ -1026,7 +1020,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws InvoiceApiException {
 
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID invoiceId = UUID.fromString(invoiceIdString);
         invoiceApi.voidInvoice(invoiceId, callContext);
         return Response.status(Response.Status.OK).build();
     }
@@ -1060,8 +1053,8 @@ public class InvoiceResource extends JaxRsResourceBase {
             } else {
                 this.dryRunType = input.getDryRunType() != null ? DryRunType.valueOf(input.getDryRunType()) : DryRunType.TARGET_DATE;
                 this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
-                this.subscriptionId = input.getSubscriptionId() != null ? UUID.fromString(input.getSubscriptionId()) : null;
-                this.bundleId = input.getBundleId() != null ? UUID.fromString(input.getBundleId()) : null;
+                this.subscriptionId = input.getSubscriptionId();
+                this.bundleId = input.getBundleId();
                 this.effectiveDate = input.getEffectiveDate();
                 this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
                 final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
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 f0490db..a6ed103 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
@@ -162,7 +162,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
     public Response addBlockingState(final BlockingStateJson json,
-                                     final String id,
+                                     final UUID blockableId,
                                      final BlockingStateType type,
                                      final String requestedDate,
                                      final List<String> pluginPropertiesString,
@@ -173,7 +173,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final UUID blockableId = UUID.fromString(id);
 
         final boolean isBlockBilling = (json.isBlockBilling() != null && json.isBlockBilling());
         final boolean isBlockEntitlement = (json.isBlockEntitlement() != null && json.isBlockEntitlement());
@@ -277,7 +276,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         for (final CustomFieldJson cur : customFields) {
             verifyNonNullOrEmpty(cur.getCustomFieldId(), "CustomFieldJson id needs to be set");
             verifyNonNullOrEmpty(cur.getValue(), "CustomFieldJson value needs to be set");
-            input.add(new StringCustomField(UUID.fromString(cur.getCustomFieldId()), cur.getName(), cur.getValue(), getObjectType(), id, context.getCreatedDate()));
+            input.add(new StringCustomField(cur.getCustomFieldId(), cur.getName(), cur.getValue(), getObjectType(), id, context.getCreatedDate()));
         }
 
         customFieldUserApi.updateCustomFields(input, context);
@@ -374,10 +373,9 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
     }
 
-    protected Payment getPaymentByIdOrKey(@Nullable final String paymentIdStr, @Nullable final String externalKey, final Iterable<PluginProperty> pluginProperties, final TenantContext tenantContext) throws PaymentApiException {
-        Preconditions.checkArgument(paymentIdStr != null || externalKey != null, "Need to set either paymentId or payment externalKey");
-        if (paymentIdStr != null) {
-            final UUID paymentId = UUID.fromString(paymentIdStr);
+    protected Payment getPaymentByIdOrKey(@Nullable final UUID paymentId, @Nullable final String externalKey, final Iterable<PluginProperty> pluginProperties, final TenantContext tenantContext) throws PaymentApiException {
+        Preconditions.checkArgument(paymentId != null || externalKey != null, "Need to set either paymentId or payment externalKey");
+        if (paymentId != null) {
             return paymentApi.getPayment(paymentId, false, false, pluginProperties, tenantContext);
         } else {
             return paymentApi.getPaymentByExternalKey(externalKey, false, false, pluginProperties, tenantContext);
@@ -446,14 +444,14 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
 
-    protected PaymentTransaction lookupPendingOrSuccessTransaction(final Payment initialPayment, @Nullable final String 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 String transactionType) throws PaymentApiException {
         final Collection<PaymentTransaction> pendingTransaction = Collections2.filter(initialPayment.getTransactions(), new Predicate<PaymentTransaction>() {
             @Override
             public boolean apply(final PaymentTransaction input) {
                 if (input.getTransactionStatus() != TransactionStatus.PENDING && input.getTransactionStatus() != TransactionStatus.SUCCESS) {
                     return false;
                 }
-                if (transactionId != null && !transactionId.equals(input.getId().toString())) {
+                if (transactionId != null && !transactionId.equals(input.getId())) {
                     return false;
                 }
                 if (transactionExternalKey != null && !transactionExternalKey.equals(input.getExternalKey())) {
@@ -476,7 +474,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
                 final String parameterValue;
                 if (transactionId != null) {
                     parameterType = "transactionId";
-                    parameterValue = transactionId;
+                    parameterValue = transactionId.toString();
                 } else if (transactionExternalKey != null) {
                     parameterType = "transactionExternalKey";
                     parameterValue = transactionExternalKey;
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
new file mode 100644
index 0000000..c845a5f
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
@@ -0,0 +1,172 @@
+/*
+ * 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.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;
+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.Swagger;
+import io.swagger.models.auth.BasicAuthDefinition;
+import io.swagger.models.parameters.BodyParameter;
+import io.swagger.models.parameters.HeaderParameter;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.PathParameter;
+import io.swagger.models.parameters.QueryParameter;
+import io.swagger.models.properties.Property;
+
+import static org.killbill.billing.jaxrs.resources.JaxrsResource.HDR_CREATED_BY;
+import static org.killbill.billing.jaxrs.resources.JaxrsResource.QUERY_AUDIT;
+
+@SwaggerDefinition
+public class KillBillApiDefinition implements ReaderListener {
+
+    public static final String BASIC_AUTH_SCHEME = "basicAuth";
+
+    @Override
+    public void beforeScan(final io.swagger.jaxrs.Reader reader, final Swagger swagger) {
+        BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
+        swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
+    }
+
+    @Override
+    public void afterScan(final io.swagger.jaxrs.Reader reader, final Swagger swagger) {
+
+        final HeaderParameter apiKeyParam = new HeaderParameter();
+        apiKeyParam.setName("X-Killbill-ApiKey");
+        apiKeyParam.setType("string");
+        apiKeyParam.setRequired(true);
+
+        final HeaderParameter apiSecretParam = new HeaderParameter();
+        apiSecretParam.setName("X-Killbill-ApiSecret");
+        apiSecretParam.setType("string");
+        apiSecretParam.setRequired(true);
+
+        for (final String pathName : swagger.getPaths().keySet()) {
+            final Path path = swagger.getPaths().get(pathName);
+            decorateOperation(path.getGet(), pathName, "GET", apiKeyParam, apiSecretParam);
+            decorateOperation(path.getPost(), pathName, "POST", apiKeyParam, apiSecretParam);
+            decorateOperation(path.getPut(), pathName, "PUT", apiKeyParam, apiSecretParam);
+            decorateOperation(path.getDelete(), pathName, "DELETE", apiKeyParam, apiSecretParam);
+            decorateOperation(path.getOptions(), pathName, "OPTIONS", apiKeyParam, apiSecretParam);
+
+        }
+
+        for (final Model m : swagger.getDefinitions().values()) {
+            if (m.getProperties() != null) {
+                for (final Property p : m.getProperties().values()) {
+                    p.setReadOnly(false);
+                }
+            }
+        }
+    }
+
+    private void decorateOperation(final Operation op, final String pathName, final String httpMethod, final HeaderParameter apiKeyParam, final HeaderParameter apiSecretParam) {
+        if (op != null) {
+            op.addSecurity(BASIC_AUTH_SCHEME, null);
+            if (requiresTenantInformation(pathName, httpMethod)) {
+                op.addParameter(apiKeyParam);
+                op.addParameter(apiSecretParam);
+            }
+
+            for (Parameter p : op.getParameters()) {
+                if (p instanceof BodyParameter) {
+                    p.setRequired(true);
+                } else if (p instanceof PathParameter) {
+                    p.setRequired(true);
+                } else if (p instanceof HeaderParameter) {
+                    if (p.getName().equals(HDR_CREATED_BY)) {
+                        p.setRequired(true);
+                    }
+                } 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>() {
+                            @Override
+                            public String apply(final AuditLevel input) {
+                                return input.toString();
+                            }
+                        }));
+                        qp.setEnum(values);
+                    }
+                }
+            }
+        }
+    }
+
+    public static boolean requiresTenantInformation(final String path, final String httpMethod) {
+        boolean shouldSkipTenantInfoForRequests = (
+                // Chicken - egg problem
+                isTenantCreationRequest(path, httpMethod) ||
+                // Retrieve user permissions should not require tenant info since this is cross tenants
+                isPermissionRequest(path) ||
+                // Node request are cross tenant
+                isNodeInfoRequest(path) ||
+                // See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
+                isOptionsRequest(httpMethod) ||
+                // Shift the responsibility to the plugin
+                isPluginRequest(path) ||
+                // Static resources (welcome screen, Swagger, etc.)
+                isNotKbNorPluginResourceRequest(path, httpMethod));
+        return !shouldSkipTenantInfoForRequests;
+    }
+
+    private static boolean isPermissionRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.SECURITY_PATH);
+    }
+
+    private static boolean isTenantCreationRequest(final String path, final String httpMethod) {
+        return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isNodeInfoRequest(final String path) {
+        return JaxrsResource.NODES_INFO_PATH.equals(path);
+    }
+
+    private static boolean isOptionsRequest(final String httpMethod) {
+        return "OPTIONS".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isNotKbNorPluginResourceRequest(final String path, final String httpMethod) {
+        return !isPluginRequest(path) && !isKbApiRequest(path) && "GET".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isKbApiRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.PREFIX);
+    }
+
+    private static boolean isPluginRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.PLUGINS_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 e1d38f7..69e0d40 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
@@ -72,7 +72,7 @@ import io.swagger.annotations.ApiResponses;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Path(JaxrsResource.NODES_INFO_PATH)
-@Api(value = JaxrsResource.NODES_INFO_PATH, description = "Operations to retrieve nodes info")
+@Api(value = JaxrsResource.NODES_INFO_PATH, description = "Operations to retrieve nodes info", tags="NodesInfo")
 public class NodesInfoResource extends JaxRsResourceBase {
 
     private final KillbillNodesApi killbillInfoApi;
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 82b4c72..6281a83 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
@@ -61,7 +61,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_XML;
 
 @Singleton
 @Path(JaxrsResource.OVERDUE_PATH)
-@Api(value = JaxrsResource.OVERDUE_PATH, description = "Overdue information")
+@Api(value = JaxrsResource.OVERDUE_PATH, description = "Overdue information", tags="Overdue")
 public class OverdueResource extends JaxRsResourceBase {
 
     private final OverdueApi overdueApi;
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 671c99d..818b4ff 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
@@ -67,7 +67,7 @@ import static javax.ws.rs.core.MediaType.WILDCARD;
 
 @Singleton
 @Path(JaxrsResource.PAYMENT_GATEWAYS_PATH)
-@Api(value = JaxrsResource.PAYMENT_GATEWAYS_PATH, description = "HPP endpoints")
+@Api(value = JaxrsResource.PAYMENT_GATEWAYS_PATH, description = "HPP endpoints", tags="PaymentGateway")
 public class PaymentGatewayResource extends ComboPaymentResource {
 
     private final PaymentGatewayApi paymentGatewayApi;
@@ -130,8 +130,8 @@ public class PaymentGatewayResource extends ComboPaymentResource {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid accountId supplied"),
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response buildFormDescriptor(final HostedPaymentPageFieldsJson json,
-                                        @PathParam("accountId") final String accountIdString,
-                                        @QueryParam(QUERY_PAYMENT_METHOD_ID) final String paymentMethodIdStr,
+                                        @PathParam("accountId") final UUID accountId,
+                                        @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,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
@@ -141,10 +141,9 @@ public class PaymentGatewayResource extends ComboPaymentResource {
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
-        final UUID accountId = UUID.fromString(accountIdString);
         final CallContext callContext = context.createCallContextWithAccountId(accountId, createdBy, reason, comment, request);
         final Account account = accountUserApi.getAccountById(accountId, callContext);
-        final UUID paymentMethodId = paymentMethodIdStr == null ? account.getPaymentMethodId() : UUID.fromString(paymentMethodIdStr);
+        final UUID paymentMethodId = inputPaymentMethodId == null ? account.getPaymentMethodId() : inputPaymentMethodId;
 
         validatePaymentMethodForAccount(accountId, paymentMethodId, callContext);
 
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 e765694..89e3ac5 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
@@ -71,6 +71,7 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 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;
 
@@ -78,7 +79,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.PAYMENT_METHODS_PATH)
-@Api(value = JaxrsResource.PAYMENT_METHODS_PATH, description = "Operations on payment methods")
+@Api(value = JaxrsResource.PAYMENT_METHODS_PATH, description = "Operations on payment methods", tags="PaymentMethod")
 public class PaymentMethodResource extends JaxRsResourceBase {
 
     @Inject
@@ -100,7 +101,7 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a payment method by id", response = PaymentMethodJson.class)
     @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 String paymentMethodId,
+    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,
@@ -109,7 +110,7 @@ public class PaymentMethodResource extends JaxRsResourceBase {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
 
-        final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodId), includedDeleted, withPluginInfo, pluginProperties, tenantContext);
+        final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(paymentMethodId, includedDeleted, withPluginInfo, pluginProperties, tenantContext);
         final Account account = accountUserApi.getAccountById(paymentMethod.getAccountId(), tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(paymentMethod.getAccountId(), auditMode.getLevel(), tenantContext);
         final PaymentMethodJson json = PaymentMethodJson.toPaymentMethodJson(account, paymentMethod, accountAuditLogs);
@@ -122,7 +123,7 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @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(@QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+    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,
@@ -260,7 +261,7 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @ApiOperation(value = "Delete a payment method")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentMethodId supplied"),
                            @ApiResponse(code = 404, message = "Account or payment method not found")})
-    public Response deletePaymentMethod(@PathParam("paymentMethodId") final String paymentMethodId,
+    public Response deletePaymentMethod(@PathParam("paymentMethodId") final UUID paymentMethodId,
                                         @QueryParam(QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF) @DefaultValue("false") final Boolean deleteDefaultPaymentMethodWithAutoPayOff,
                                         @QueryParam(QUERY_FORCE_DEFAULT_PM_DELETION) @DefaultValue("false") final Boolean forceDefaultPaymentMethodDeletion,
                                         @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -271,10 +272,10 @@ public class PaymentMethodResource extends JaxRsResourceBase {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodId), false, false, pluginProperties, callContext);
+        final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(paymentMethodId, false, false, pluginProperties, callContext);
         final Account account = accountUserApi.getAccountById(paymentMethod.getAccountId(), callContext);
 
-        paymentApi.deletePaymentMethod(account, UUID.fromString(paymentMethodId), deleteDefaultPaymentMethodWithAutoPayOff, forceDefaultPaymentMethodDeletion, pluginProperties, callContext);
+        paymentApi.deletePaymentMethod(account, paymentMethodId, deleteDefaultPaymentMethodWithAutoPayOff, forceDefaultPaymentMethodDeletion, pluginProperties, callContext);
 
         return Response.status(Status.OK).build();
     }
@@ -285,10 +286,10 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve payment method custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment method id supplied")})
-    public Response getCustomFields(@PathParam("paymentMethodId") final String paymentMethodId,
+    public Response getCustomFields(@PathParam("paymentMethodId") final UUID paymentMethodId,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(paymentMethodId), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(paymentMethodId, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -298,14 +299,14 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @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 String paymentMethodId,
+    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 {
-        return super.createCustomFields(UUID.fromString(paymentMethodId), customFields,
+        return super.createCustomFields(paymentMethodId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -317,13 +318,13 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @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 String paymentMethodId,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(paymentMethodId), customFields,
+        return super.modifyCustomFields(paymentMethodId, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -335,13 +336,13 @@ public class PaymentMethodResource extends JaxRsResourceBase {
     @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 String paymentMethodId,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(paymentMethodId), customFieldList,
+        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 4e11dc8..6c7d14c 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
@@ -81,13 +81,14 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 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.PAYMENTS_PATH)
-@Api(value = JaxrsResource.PAYMENTS_PATH, description = "Operations on payments")
+@Api(value = JaxrsResource.PAYMENTS_PATH, description = "Operations on payments", tags="Payment")
 public class PaymentResource extends ComboPaymentResource {
 
     private static final String ID_PARAM_NAME = "paymentId";
@@ -111,16 +112,15 @@ public class PaymentResource extends ComboPaymentResource {
     @ApiOperation(value = "Retrieve a payment by id", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentId supplied"),
                            @ApiResponse(code = 404, message = "Payment not found")})
-    public Response getPayment(@PathParam("paymentId") final String paymentIdStr,
+    public Response getPayment(@PathParam("paymentId") final UUID paymentId,
                                @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 UUID paymentIdId = UUID.fromString(paymentIdStr);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Payment payment = paymentApi.getPayment(paymentIdId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
+        final Payment payment = paymentApi.getPayment(paymentId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(payment.getAccountId(), auditMode.getLevel(), tenantContext);
         final PaymentJson result = new PaymentJson(payment, accountAuditLogs);
         return Response.status(Response.Status.OK).entity(result).build();
@@ -133,7 +133,7 @@ public class PaymentResource extends ComboPaymentResource {
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Payment not found")})
     public Response getPaymentByExternalKey(@QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                             @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts,
-                                            @QueryParam(QUERY_EXTERNAL_KEY) final String paymentExternalKey,
+                                            @ApiParam(required=true) @QueryParam(QUERY_EXTERNAL_KEY) final String paymentExternalKey,
                                             @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 {
@@ -252,7 +252,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                        @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,
@@ -260,7 +260,7 @@ 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, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return completeTransactionInternalWithoutPayment(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
 
@@ -309,7 +309,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                         @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,
@@ -317,7 +317,7 @@ 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 captureAuthorizationInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return captureAuthorizationInternal(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
     @TimedResource(name = "captureAuthorization")
@@ -344,7 +344,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response captureAuthorizationInternal(final PaymentTransactionJson json,
-                                                  @Nullable final String paymentIdStr,
+                                                  @Nullable final UUID paymentId,
                                                   final List<String> paymentControlPluginNames,
                                                   final List<String> pluginPropertiesString,
                                                   final String createdBy,
@@ -360,7 +360,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
         final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
+        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());
@@ -387,7 +387,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                  @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,
@@ -395,7 +395,7 @@ 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 refundPaymentInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return refundPaymentInternal(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
     @TimedResource(name = "refundPayment")
@@ -424,7 +424,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response refundPaymentInternal(final PaymentTransactionJson json,
-                                           @Nullable final String paymentIdStr,
+                                           @Nullable final UUID paymentId,
                                            final List<String> paymentControlPluginNames,
                                            final List<String> pluginPropertiesString,
                                            final String createdBy,
@@ -441,7 +441,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
+        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());
@@ -469,7 +469,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                @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,
@@ -477,7 +477,7 @@ 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 voidPaymentInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return voidPaymentInternal(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
     @TimedResource(name = "voidPayment")
@@ -504,7 +504,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response voidPaymentInternal(final PaymentTransactionJson json,
-                                         @Nullable final String paymentIdStr,
+                                         @Nullable final UUID paymentId,
                                          final List<String> paymentControlPluginNames,
                                          final List<String> pluginPropertiesString,
                                          final String createdBy,
@@ -517,7 +517,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
+        final Payment initialPayment = getPaymentByIdOrKey(paymentId, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
 
@@ -544,7 +544,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                      @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,
@@ -552,7 +552,7 @@ 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 chargebackPaymentInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return chargebackPaymentInternal(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
     @TimedResource(name = "chargebackPayment")
@@ -580,7 +580,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response chargebackPaymentInternal(final PaymentTransactionJson json,
-                                               @Nullable final String paymentIdStr,
+                                               @Nullable final UUID paymentId,
                                                final List<String> paymentControlPluginNames,
                                                final List<String> pluginPropertiesString,
                                                final String createdBy,
@@ -596,7 +596,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
+        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());
@@ -623,7 +623,7 @@ public class PaymentResource extends ComboPaymentResource {
                            @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 String paymentIdStr,
+                                              @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,
@@ -631,7 +631,7 @@ 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 chargebackReversalPaymentInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+        return chargebackReversalPaymentInternal(json, paymentId, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
     }
 
     @TimedResource(name = "chargebackReversalPayment")
@@ -659,7 +659,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response chargebackReversalPaymentInternal(final PaymentTransactionJson json,
-                                                       @Nullable final String paymentIdStr,
+                                                       @Nullable final UUID paymentId,
                                                        final List<String> paymentControlPluginNames,
                                                        final List<String> pluginPropertiesString,
                                                        final String createdBy,
@@ -672,7 +672,7 @@ public class PaymentResource extends ComboPaymentResource {
 
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
+        final Payment initialPayment = getPaymentByIdOrKey(paymentId, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
 
@@ -749,14 +749,14 @@ public class PaymentResource extends ComboPaymentResource {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Cancels a scheduled payment attempt retry")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionId supplied")})
-    public Response cancelScheduledPaymentTransactionById(@PathParam("paymentTransactionId") final String paymentTransactionId,
+    public Response cancelScheduledPaymentTransactionById(@PathParam("paymentTransactionId") final UUID paymentTransactionId,
                                                           @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 CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        paymentApi.cancelScheduledPaymentTransaction(UUID.fromString(paymentTransactionId), callContext);
+        paymentApi.cancelScheduledPaymentTransaction(paymentTransactionId, callContext);
         return Response.status(Status.OK).build();
     }
 
@@ -767,7 +767,7 @@ public class PaymentResource extends ComboPaymentResource {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Cancels a scheduled payment attempt retry")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionExternalKey supplied")})
-    public Response cancelScheduledPaymentTransactionByExternalKey(@QueryParam(QUERY_TRANSACTION_EXTERNAL_KEY) final String paymentTransactionExternalKey,
+    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,
                                                                    @HeaderParam(HDR_COMMENT) final String comment,
@@ -787,10 +787,10 @@ public class PaymentResource extends ComboPaymentResource {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve payment custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid payment id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -800,14 +800,14 @@ public class PaymentResource extends ComboPaymentResource {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -818,13 +818,13 @@ public class PaymentResource extends ComboPaymentResource {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -835,13 +835,13 @@ public class PaymentResource extends ComboPaymentResource {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -852,12 +852,11 @@ public class PaymentResource extends ComboPaymentResource {
     @ApiOperation(value = "Retrieve payment payment tags", response = TagJson.class, responseContainer = "List")
     @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 String id,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final UUID paymentId = UUID.fromString(id);
         final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
         return super.getTags(payment.getAccountId(), paymentId, auditMode, includedDeleted, tenantContext);
     }
@@ -869,14 +868,14 @@ public class PaymentResource extends ComboPaymentResource {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(paymentId, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -887,13 +886,13 @@ public class PaymentResource extends ComboPaymentResource {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        return super.deleteTags(paymentId, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -903,7 +902,7 @@ public class PaymentResource extends ComboPaymentResource {
     }
 
     private Response completeTransactionInternalWithoutPayment(final PaymentTransactionJson json,
-                                                               @Nullable final String paymentIdStr,
+                                                               @Nullable final UUID paymentId,
                                                                final List<String> paymentControlPluginNames,
                                                                final Iterable<String> pluginPropertiesString,
                                                                final String createdBy,
@@ -919,7 +918,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
 
         final CallContext callContextNoAccountId = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContextNoAccountId);
+        final Payment initialPayment = getPaymentByIdOrKey(paymentId, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContextNoAccountId);
 
         return completeTransactionInternal(json, initialPayment, paymentControlPluginNames, pluginProperties, callContextNoAccountId, createdBy, reason, comment, uriInfo, request);
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PluginInfoResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PluginInfoResource.java
index ffbd88c..936ba41 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PluginInfoResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PluginInfoResource.java
@@ -48,7 +48,7 @@ import io.swagger.annotations.ApiOperation;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Path(JaxrsResource.PLUGINS_INFO_PATH)
-@Api(value = JaxrsResource.PLUGINS_INFO_PATH, description = "Operations on plugins")
+@Api(value = JaxrsResource.PLUGINS_INFO_PATH, description = "Operations on plugins", tags="PluginInfo")
 public class PluginInfoResource extends JaxRsResourceBase {
 
     private final PluginsInfoApi pluginsInfoApi;
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 60e55b5..5b85cf5 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
@@ -65,7 +65,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.SECURITY_PATH)
-@Api(value = JaxrsResource.SECURITY_PATH, description = "Information about RBAC")
+@Api(value = JaxrsResource.SECURITY_PATH, description = "Information about RBAC", tags="Security")
 public class SecurityResource extends JaxRsResourceBase {
 
     private final SecurityApi securityApi;
@@ -147,7 +147,7 @@ public class SecurityResource extends JaxRsResourceBase {
     @GET
     @Produces(APPLICATION_JSON)
     @Path("/users/{username:" + ANYTHING_PATTERN + "}/roles")
-    @ApiOperation(value = "Get roles associated to a user")
+    @ApiOperation(value = "Get roles associated to a user", response = UserRolesJson.class)
     public Response getUserRoles(@PathParam("username") final String username,
                                  @javax.ws.rs.core.Context final HttpServletRequest request,
                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
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 ae71972..5f8cf95 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
@@ -76,7 +76,8 @@ import org.killbill.billing.events.PaymentErrorInternalEvent;
 import org.killbill.billing.events.PaymentInfoInternalEvent;
 import org.killbill.billing.events.PaymentPluginErrorInternalEvent;
 import org.killbill.billing.jaxrs.json.BlockingStateJson;
-import org.killbill.billing.jaxrs.json.BulkBaseSubscriptionAndAddOnsJson;
+import org.killbill.billing.jaxrs.json.BulkSubscriptionsBundleJson;
+import org.killbill.billing.jaxrs.json.BundleJson;
 import org.killbill.billing.jaxrs.json.CustomFieldJson;
 import org.killbill.billing.jaxrs.json.PhasePriceOverrideJson;
 import org.killbill.billing.jaxrs.json.SubscriptionJson;
@@ -115,7 +116,7 @@ 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")
+@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);
@@ -150,12 +151,11 @@ 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 String subscriptionId,
+    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 {
-        final UUID uuid = UUID.fromString(subscriptionId);
         final TenantContext context = this.context.createTenantContextNoAccountId(request);
-        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(uuid, context);
+        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(subscriptionId, context);
         final Account account = accountUserApi.getAccountById(subscription.getAccountId(), context);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(subscription.getAccountId(), auditMode.getLevel(), context);
         final SubscriptionJson json = new SubscriptionJson(subscription, account.getCurrency(), accountAuditLogs);
@@ -228,7 +228,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
             private UUID getBundleIdForAddOnCreation(final SubscriptionJson entitlement) throws SubscriptionApiException {
 
                 if (entitlement.getBundleId() != null) {
-                    return UUID.fromString(entitlement.getBundleId());
+                    return entitlement.getBundleId();
                 }
                 // If user only specified the externalKey we need to fech the bundle (expensive operation) to extract the bundleId
                 final SubscriptionBundle bundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey(entitlement.getExternalKey(), callContext);
@@ -255,7 +255,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/createEntitlementWithAddOns")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create an entitlement with addOn products")
+    @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 */
@@ -271,7 +271,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                                                 @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<BulkBaseSubscriptionAndAddOnsJson> entitlementsWithAddOns = ImmutableList.of(new BulkBaseSubscriptionAndAddOnsJson(entitlements));
+        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);
     }
 
@@ -280,9 +280,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Path("/createEntitlementsWithAddOns")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Create multiple entitlements with addOn products")
+    @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<BulkBaseSubscriptionAndAddOnsJson> entitlementsWithAddOns,
+    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,
@@ -300,7 +300,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     }
 
 
-    public Response createEntitlementsWithAddOnsInternal(final List<BulkBaseSubscriptionAndAddOnsJson> entitlementsWithAddOns,
+    public Response createEntitlementsWithAddOnsInternal(final List<BulkSubscriptionsBundleJson> entitlementsWithAddOns,
                                                  final String requestedDate,
                                                  final String entitlementDate,
                                                  final String billingDate,
@@ -322,10 +322,10 @@ public class SubscriptionResource extends JaxRsResourceBase {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final Account account = accountUserApi.getAccountById(UUID.fromString(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns().get(0).getAccountId()), callContext);
+        final Account account = accountUserApi.getAccountById(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns().get(0).getAccountId(), callContext);
 
         final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
-        for (BulkBaseSubscriptionAndAddOnsJson bulkBaseEntitlementWithAddOns : entitlementsWithAddOns) {
+        for (BulkSubscriptionsBundleJson bulkBaseEntitlementWithAddOns : entitlementsWithAddOns) {
             final Iterable<SubscriptionJson> baseEntitlements = Iterables.filter(
                     bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
                         @Override
@@ -503,15 +503,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Un-cancel an entitlement")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response uncancelEntitlementPlan(@PathParam("subscriptionId") final String subscriptionId,
+    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 {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID uuid = UUID.fromString(subscriptionId);
-        final Entitlement current = entitlementApi.getEntitlementForId(uuid, context.createCallContextNoAccountId(createdBy, reason, comment, request));
+        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();
     }
@@ -523,15 +522,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Undo a pending change plan on an entitlement")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response undoChangeEntitlementPlan(@PathParam("subscriptionId") final String subscriptionId,
+    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 {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
-        final UUID uuid = UUID.fromString(subscriptionId);
-        final Entitlement current = entitlementApi.getEntitlementForId(uuid, context.createCallContextNoAccountId(createdBy, reason, comment, request));
+        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();
     }
@@ -545,7 +543,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
     public Response changeEntitlementPlan(final SubscriptionJson entitlement,
-                                          @PathParam("subscriptionId") final String subscriptionId,
+                                          @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,
@@ -572,9 +570,8 @@ public class SubscriptionResource extends JaxRsResourceBase {
             @Override
             public Response doOperation(final CallContext ctx) throws EntitlementApiException, InterruptedException,
                                                                       TimeoutException, AccountApiException {
-                final UUID uuid = UUID.fromString(subscriptionId);
 
-                final Entitlement current = entitlementApi.getEntitlementForId(uuid, callContext);
+                final Entitlement current = entitlementApi.getEntitlementForId(subscriptionId, callContext);
                 final LocalDate inputLocalDate = toLocalDate(requestedDate);
                 final Entitlement newEntitlement;
 
@@ -626,7 +623,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String id,
+                                                 @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,
@@ -644,7 +641,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Cancel an entitlement plan")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
                            @ApiResponse(code = 404, message = "Entitlement not found")})
-    public Response cancelEntitlementPlan(@PathParam("subscriptionId") final String subscriptionId,
+    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,
@@ -668,9 +665,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
             public Response doOperation(final CallContext ctx)
                     throws EntitlementApiException, InterruptedException,
                            TimeoutException, AccountApiException, SubscriptionApiException {
-                final UUID uuid = UUID.fromString(subscriptionId);
-
-                final Entitlement current = entitlementApi.getEntitlementForId(uuid, ctx);
+                final Entitlement current = entitlementApi.getEntitlementForId(subscriptionId, ctx);
                 final LocalDate inputLocalDate = toLocalDate(requestedDate);
                 final Entitlement newEntitlement;
                 if (billingPolicyString == null && entitlementPolicyString == null) {
@@ -718,7 +713,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+                                          @PathParam(ID_PARAM_NAME) final UUID subscriptionId,
                                           @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,
@@ -733,8 +728,6 @@ public class SubscriptionResource extends JaxRsResourceBase {
         LocalDate effectiveFromDate = toLocalDate(effectiveFromDateStr);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final UUID subscriptionId = UUID.fromString(id);
-
         final Entitlement entitlement = entitlementApi.getEntitlementForId(subscriptionId, callContext);
         if (effectiveFromDateStr != null) {
             final Account account = accountUserApi.getAccountById(entitlement.getAccountId(), callContext);
@@ -867,10 +860,10 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve subscription custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @POST
@@ -879,14 +872,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -896,13 +889,13 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -912,14 +905,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -929,11 +922,10 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve subscription tags", response = TagJson.class, responseContainer = "List")
     @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 String subscriptionIdString,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
-        final UUID subscriptionId = UUID.fromString(subscriptionIdString);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(subscriptionId, tenantContext);
         return super.getTags(subscription.getAccountId(), subscriptionId, auditMode, includedDeleted, tenantContext);
@@ -945,14 +937,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -962,13 +954,13 @@ public class SubscriptionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        return super.deleteTags(id, tagList,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -980,12 +972,12 @@ public class SubscriptionResource extends JaxRsResourceBase {
     private Account getAccountFromSubscriptionJson(final SubscriptionJson entitlementJson, final CallContext callContext) throws SubscriptionApiException, AccountApiException, EntitlementApiException {
         final UUID accountId;
         if (entitlementJson.getAccountId() != null) {
-            accountId = UUID.fromString(entitlementJson.getAccountId());
+            accountId = entitlementJson.getAccountId();
         } else if (entitlementJson.getSubscriptionId() != null) {
-            final Entitlement entitlement = entitlementApi.getEntitlementForId(UUID.fromString(entitlementJson.getSubscriptionId()), callContext);
+            final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementJson.getSubscriptionId(), callContext);
             accountId = entitlement.getAccountId();
         } else {
-            final SubscriptionBundle subscriptionBundle = subscriptionApi.getSubscriptionBundle(UUID.fromString(entitlementJson.getBundleId()), callContext);
+            final SubscriptionBundle subscriptionBundle = subscriptionApi.getSubscriptionBundle(entitlementJson.getBundleId(), callContext);
             accountId = subscriptionBundle.getAccountId();
         }
         return accountUserApi.getAccountById(accountId, callContext);
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 efa5c24..7f5d997 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
@@ -64,7 +64,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.TAG_DEFINITIONS_PATH)
-@Api(value = JaxrsResource.TAG_DEFINITIONS_PATH, description = "Operations on tag definitions")
+@Api(value = JaxrsResource.TAG_DEFINITIONS_PATH, description = "Operations on tag definitions", tags="TagDefinition")
 public class TagDefinitionResource extends JaxRsResourceBase {
 
     @Inject
@@ -104,11 +104,11 @@ public class TagDefinitionResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve a tag definition", response = TagDefinitionJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tagDefinitionId supplied")})
-    public Response getTagDefinition(@PathParam("tagDefinitionId") final String tagDefId,
+    public Response getTagDefinition(@PathParam("tagDefinitionId") final UUID tagDefId,
                                      @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                      @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final TagDefinition tagDefinition = tagUserApi.getTagDefinition(UUID.fromString(tagDefId), tenantContext);
+        final TagDefinition tagDefinition = tagUserApi.getTagDefinition(tagDefId, tenantContext);
         final List<AuditLog> auditLogs = auditUserApi.getAuditLogs(tagDefinition.getId(), ObjectType.TAG_DEFINITION, auditMode.getLevel(), tenantContext);
         final TagDefinitionJson json = new TagDefinitionJson(tagDefinition, auditLogs);
         return Response.status(Status.OK).entity(json).build();
@@ -144,12 +144,12 @@ public class TagDefinitionResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Delete a tag definition")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tagDefinitionId supplied")})
-    public Response deleteTagDefinition(@PathParam("tagDefinitionId") final String tagDefId,
+    public Response deleteTagDefinition(@PathParam("tagDefinitionId") final UUID tagDefId,
                                         @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 TagDefinitionApiException {
-        tagUserApi.deleteTagDefinition(UUID.fromString(tagDefId), context.createCallContextNoAccountId(createdBy, reason, comment, request));
+        tagUserApi.deleteTagDefinition(tagDefId, context.createCallContextNoAccountId(createdBy, reason, comment, request));
         return Response.status(Status.NO_CONTENT).build();
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagResource.java
index c634f84..e194d3c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagResource.java
@@ -61,7 +61,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.TAGS_PATH)
-@Api(value = JaxrsResource.TAGS_PATH, description = "Operations on tags")
+@Api(value = JaxrsResource.TAGS_PATH, description = "Operations on tags", tags="Tag")
 public class TagResource extends JaxRsResourceBase {
 
     @Inject
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 664fcea..33fa7d7 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
@@ -75,7 +75,7 @@ import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
 
 @Singleton
 @Path(JaxrsResource.TENANTS_PATH)
-@Api(value = JaxrsResource.TENANTS_PATH, description = "Operations on tenants")
+@Api(value = JaxrsResource.TENANTS_PATH, description = "Operations on tenants", tags="Tenant")
 public class TenantResource extends JaxRsResourceBase {
 
     private final TenantUserApi tenantApi;
@@ -104,8 +104,8 @@ public class TenantResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a tenant by id", response = TenantJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid tenantId supplied"),
                            @ApiResponse(code = 404, message = "Tenant not found")})
-    public Response getTenant(@PathParam("tenantId") final String tenantId) throws TenantApiException {
-        final Tenant tenant = tenantApi.getTenantById(UUID.fromString(tenantId));
+    public Response getTenant(@PathParam("tenantId") final UUID tenantId) throws TenantApiException {
+        final Tenant tenant = tenantApi.getTenantById(tenantId);
         return Response.status(Status.OK).entity(new TenantJson(tenant)).build();
     }
 
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 5e01d3c..13e2206 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
@@ -90,7 +90,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 //
 //
 @Path(JaxrsResource.TEST_PATH)
-@Api(value = JaxrsResource.TEST_PATH, description = "Operations for testing")
+@Api(value = JaxrsResource.TEST_PATH, description = "Operations for testing", hidden=true)
 public class TestResource extends JaxRsResourceBase {
 
     private static final Logger log = LoggerFactory.getLogger(TestResource.class);
@@ -181,7 +181,6 @@ public class TestResource extends JaxRsResourceBase {
 
         final ClockMock testClock = getClockMock();
         if (requestedClockDate == null) {
-            log.info("************      RESETTING CLOCK to " + clock.getUTCNow());
             testClock.resetDeltaFromReality();
         } else {
             final DateTime newTime = DATE_TIME_FORMATTER.parseDateTime(requestedClockDate).toDateTime(DateTimeZone.UTC);
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 414b01d..31f6522 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
@@ -73,7 +73,7 @@ import io.swagger.annotations.ApiResponses;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Path(JaxrsResource.PAYMENT_TRANSACTIONS_PATH)
-@Api(value = JaxrsResource.PAYMENT_TRANSACTIONS_PATH, description = "Operations on payment transactions")
+@Api(value = JaxrsResource.PAYMENT_TRANSACTIONS_PATH, description = "Operations on payment transactions", tags="PaymentTransaction")
 public class TransactionResource extends JaxRsResourceBase {
 
     private static final String ID_PARAM_NAME = "transactionId";
@@ -96,16 +96,15 @@ public class TransactionResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve a payment by transaction id", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Payment not found")})
-    public Response getPaymentByTransactionId(@PathParam("transactionId") final String transactionIdStr,
+    public Response getPaymentByTransactionId(@PathParam("transactionId") final UUID transactionId,
                                               @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 UUID transactionIdId = UUID.fromString(transactionIdStr);
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Payment payment = paymentApi.getPaymentByTransactionId(transactionIdId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
+        final Payment payment = paymentApi.getPaymentByTransactionId(transactionId, withPluginInfo, withAttempts, pluginProperties, tenantContext);
         final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(payment.getAccountId(), auditMode.getLevel(), tenantContext);
         final PaymentJson result = new PaymentJson(payment, accountAuditLogs);
         return Response.status(Response.Status.OK).entity(result).build();
@@ -120,7 +119,7 @@ public class TransactionResource extends JaxRsResourceBase {
     @ApiResponses(value = {@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 String transactionIdStr,
+                                       @PathParam("transactionId") final UUID transactionId,
                                        @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
                                        @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                        @HeaderParam(HDR_REASON) final String reason,
@@ -134,12 +133,12 @@ public class TransactionResource extends JaxRsResourceBase {
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final UUID paymentId = UUID.fromString(json.getPaymentId());
+        final UUID paymentId = json.getPaymentId();
         final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
         final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
 
         final boolean success = TransactionStatus.SUCCESS.name().equals(json.getStatus());
-        final Payment result = paymentApi.notifyPendingTransactionOfStateChangedWithPaymentControl(account, UUID.fromString(transactionIdStr), success, paymentOptions, callContext);
+        final Payment result = paymentApi.notifyPendingTransactionOfStateChangedWithPaymentControl(account, transactionId, success, paymentOptions, callContext);
 
         return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", result.getId(), request);
     }
@@ -151,10 +150,10 @@ public class TransactionResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve payment transaction custom fields", response = CustomFieldJson.class, responseContainer = "List")
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid transaction id supplied")})
-    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final UUID id,
                                     @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), auditMode, context.createTenantContextNoAccountId(request));
+        return super.getCustomFields(id, auditMode, context.createTenantContextNoAccountId(request));
     }
 
     @TimedResource
@@ -164,14 +163,14 @@ public class TransactionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createCustomFields(UUID.fromString(id), customFields,
+        return super.createCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request), uriInfo, request);
     }
 
@@ -183,13 +182,13 @@ public class TransactionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.modifyCustomFields(UUID.fromString(id), customFields,
+        return super.modifyCustomFields(id, customFields,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -201,13 +200,13 @@ public class TransactionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
+        return super.deleteCustomFields(id, customFieldList,
                                         context.createCallContextNoAccountId(createdBy, reason, comment, request));
     }
 
@@ -218,13 +217,13 @@ public class TransactionResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve payment transaction tags", response = TagJson.class, responseContainer = "List")
     @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 String id,
+    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,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
-        final Payment payment = paymentApi.getPaymentByTransactionId(UUID.fromString(id), false, false, ImmutableList.<PluginProperty>of(), tenantContext);
-        return super.getTags(payment.getAccountId(), UUID.fromString(id), auditMode, includedDeleted, tenantContext);
+        final Payment payment = paymentApi.getPaymentByTransactionId(id, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
+        return super.getTags(payment.getAccountId(), id, auditMode, includedDeleted, tenantContext);
     }
 
     @TimedResource
@@ -234,14 +233,14 @@ public class TransactionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.createTags(UUID.fromString(id), tagList, uriInfo,
+        return super.createTags(id, tagList, uriInfo,
                                 context.createCallContextNoAccountId(createdBy, reason, comment, request), request);
     }
 
@@ -252,13 +251,13 @@ public class TransactionResource extends JaxRsResourceBase {
     @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 String id,
+    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 {
-        return super.deleteTags(UUID.fromString(id), tagList,
+        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 85029aa..1e51050 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
@@ -72,7 +72,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
 @Singleton
 @Path(JaxrsResource.USAGES_PATH)
-@Api(value = JaxrsResource.USAGES_PATH, description = "Operations on usage")
+@Api(value = JaxrsResource.USAGES_PATH, description = "Operations on usage", tags="Usage")
 public class UsageResource extends JaxRsResourceBase {
 
     private final UsageUserApi usageUserApi;
@@ -123,7 +123,7 @@ public class UsageResource extends JaxRsResourceBase {
         }
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         // Verify subscription exists..
-        final Entitlement entitlement = entitlementApi.getEntitlementForId(UUID.fromString(json.getSubscriptionId()), callContext);
+        final Entitlement entitlement = entitlementApi.getEntitlementForId(json.getSubscriptionId(), callContext);
         if (entitlement.getState() != EntitlementState.ACTIVE) {
             return Response.status(Status.BAD_REQUEST).build();
         }
@@ -139,7 +139,7 @@ public class UsageResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve usage for a subscription and unit type", response = RolledUpUsageJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Missing start date or end date")})
-    public Response getUsage(@PathParam("subscriptionId") final String subscriptionId,
+    public Response getUsage(@PathParam("subscriptionId") final UUID subscriptionId,
                              @PathParam("unitType") final String unitType,
                              @QueryParam(QUERY_START_DATE) final String startDate,
                              @QueryParam(QUERY_END_DATE) final String endDate,
@@ -152,7 +152,7 @@ public class UsageResource extends JaxRsResourceBase {
         final LocalDate usageStartDate = LOCAL_DATE_FORMATTER.parseLocalDate(startDate);
         final LocalDate usageEndDate = LOCAL_DATE_FORMATTER.parseLocalDate(endDate);
 
-        final RolledUpUsage usage = usageUserApi.getUsageForSubscription(UUID.fromString(subscriptionId), unitType, usageStartDate, usageEndDate, tenantContext);
+        final RolledUpUsage usage = usageUserApi.getUsageForSubscription(subscriptionId, unitType, usageStartDate, usageEndDate, tenantContext);
         final RolledUpUsageJson result = new RolledUpUsageJson(usage);
         return Response.status(Status.OK).entity(result).build();
     }
@@ -163,7 +163,7 @@ public class UsageResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve usage for a subscription", response = RolledUpUsageJson.class)
     @ApiResponses(value = {@ApiResponse(code = 400, message = "Missing start date or end date")})
-    public Response getAllUsage(@PathParam("subscriptionId") final String subscriptionId,
+    public Response getAllUsage(@PathParam("subscriptionId") final UUID subscriptionId,
                                 @QueryParam(QUERY_START_DATE) final String startDate,
                                 @QueryParam(QUERY_END_DATE) final String endDate,
                                 @javax.ws.rs.core.Context final HttpServletRequest request) {
@@ -178,7 +178,7 @@ public class UsageResource extends JaxRsResourceBase {
 
         // The current JAXRS API only allows to look for one transition
         final List<LocalDate> startEndDate = ImmutableList.<LocalDate>builder().add(usageStartDate).add(usageEndDate).build();
-        final List<RolledUpUsage> usage = usageUserApi.getAllUsageForSubscription(UUID.fromString(subscriptionId), startEndDate, tenantContext);
+        final List<RolledUpUsage> usage = usageUserApi.getAllUsageForSubscription(subscriptionId, startEndDate, tenantContext);
         final RolledUpUsageJson result = new RolledUpUsageJson(usage.get(0));
         return Response.status(Status.OK).entity(result).build();
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/Context.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/Context.java
index a920744..73ffa05 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/Context.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/Context.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2014 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
@@ -93,7 +93,7 @@ public class Context {
         return tenantContext;
     }
 
-    // Use REQUEST_ID_HEADER if this is provided and lloks like a UUID, if not allocate a random one.
+    // Use REQUEST_ID_HEADER if this is provided and looks like a UUID, if not allocate a random one.
     public static  UUID getOrCreateUserToken() {
         UUID userToken;
         if (Request.getPerThreadRequestData().getRequestId() != null) {
@@ -118,6 +118,11 @@ public class Context {
         }
     }
 
+    private void populateMDCContext(final CallContext callContext) {
+        // InternalCallContextFactory will do it for us
+        internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(callContext);
+    }
+
     private void populateMDCContext(final TenantContext tenantContext) {
         // InternalCallContextFactory will do it for us
         internalCallContextFactory.createInternalTenantContextWithoutAccountRecordId(tenantContext);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
index b0f210e..6d9f9b6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -106,7 +106,7 @@ public class JaxrsUriBuilder {
                 // Use "remote" value to support X-Forwarded headers (assumes RemoteIpValve or similar is configured)
                 // See https://github.com/killbill/killbill/issues/566
                 uriBuilder.scheme(request.getScheme())
-                          .host(MoreObjects.firstNonNull(jaxrsConfig.getJaxrsLocationHost(), uriInfo.getAbsolutePath().getHost())) // Should we look for X-Forwarded-By instead?
+                          .host(MoreObjects.firstNonNull(jaxrsConfig.getJaxrsLocationHost(), request.getServerName()))
                           .port(request.getServerPort());
             } else {
                 uriBuilder.scheme(uriInfo.getAbsolutePath().getScheme())
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 2161e12..71419b0 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
@@ -28,7 +28,7 @@ public class TestAccountEmailJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         final String email = UUID.randomUUID().toString();
 
         final AccountEmailJson accountEmailJson = new AccountEmailJson(accountId, email);
@@ -46,7 +46,7 @@ public class TestAccountEmailJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testToAccountEmail() throws Exception {
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         final String email = UUID.randomUUID().toString();
 
         final AccountEmailJson accountEmailJson = new AccountEmailJson(accountId, email);
@@ -54,7 +54,7 @@ public class TestAccountEmailJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(accountEmailJson.getEmail(), email);
 
         final AccountEmail accountEmail = accountEmailJson.toAccountEmail(UUID.randomUUID());
-        Assert.assertEquals(accountEmail.getAccountId().toString(), accountId);
+        Assert.assertEquals(accountEmail.getAccountId(), accountId);
         Assert.assertEquals(accountEmail.getEmail(), email);
     }
 }
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 08b1186..1e06a8e 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
@@ -32,14 +32,14 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         final String name = UUID.randomUUID().toString();
         final Integer length = 12;
         final String externalKey = UUID.randomUUID().toString();
         final String email = UUID.randomUUID().toString();
         final Integer billCycleDayLocal = 6;
         final String currency = UUID.randomUUID().toString();
-        final String paymentMethodId = UUID.randomUUID().toString();
+        final UUID paymentMethodId = UUID.randomUUID();
         final DateTime referenceTime = new DateTime();
         final String timeZone = UUID.randomUUID().toString();
         final String address1 = UUID.randomUUID().toString();
@@ -54,7 +54,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         final String notes = UUID.randomUUID().toString();
         final Boolean isMigrated = true;
         final Boolean isNotifiedForInvoice = false;
-        final String parentAccountId = UUID.randomUUID().toString();
+        final UUID parentAccountId = UUID.randomUUID();
 
         final AccountJson accountJson = new AccountJson(accountId, name, length, externalKey,
                                                         email, billCycleDayLocal, currency, parentAccountId, true, paymentMethodId,
@@ -127,12 +127,12 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(accountJson.getEmail(), account.getEmail());
         Assert.assertEquals(accountJson.getExternalKey(), account.getExternalKey());
         Assert.assertEquals(accountJson.getName(), account.getName());
-        Assert.assertEquals(accountJson.getPaymentMethodId(), account.getPaymentMethodId().toString());
+        Assert.assertEquals(accountJson.getPaymentMethodId(), account.getPaymentMethodId());
         Assert.assertEquals(accountJson.getPhone(), account.getPhone());
         Assert.assertEquals(accountJson.isMigrated(), account.isMigrated());
         Assert.assertEquals(accountJson.isNotifiedForInvoices(), account.isNotifiedForInvoices());
         Assert.assertEquals(accountJson.getState(), account.getStateOrProvince());
         Assert.assertEquals(accountJson.getTimeZone(), account.getTimeZone().toString());
-        Assert.assertEquals(accountJson.getParentAccountId(), account.getParentAccountId().toString());
+        Assert.assertEquals(accountJson.getParentAccountId(), account.getParentAccountId());
     }
 }
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 dd67ebf..2b3e45c 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
@@ -37,12 +37,12 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String someUUID = UUID.randomUUID().toString();
+        final UUID someUUID = UUID.randomUUID();
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
 
-        final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID().toString(),
+        final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID(),
                                                                       BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                       new LocalDate(),
                                                                       UUID.randomUUID().toString(),
@@ -58,9 +58,9 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
 
         final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson(null, null, "somePhaseType", BigDecimal.ONE, null, null);
 
-        final SubscriptionJson subscription = new SubscriptionJson(UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
-                                                                   UUID.randomUUID().toString(),
+        final SubscriptionJson subscription = new SubscriptionJson(UUID.randomUUID(),
+                                                                   UUID.randomUUID(),
+                                                                   UUID.randomUUID(),
                                                                    externalKey,
                                                                    new LocalDate(),
                                                                    UUID.randomUUID().toString(),
@@ -80,8 +80,8 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
                                                                    ImmutableList.of(priceOverride),
                                                                    auditLogs);
 
-        final BundleJson bundleJson = new BundleJson(someUUID, bundleId.toString(), externalKey, ImmutableList.<SubscriptionJson>of(subscription), null, auditLogs);
-        Assert.assertEquals(bundleJson.getBundleId(), bundleId.toString());
+        final BundleJson bundleJson = new BundleJson(someUUID, bundleId, externalKey, ImmutableList.<SubscriptionJson>of(subscription), null, auditLogs);
+        Assert.assertEquals(bundleJson.getBundleId(), bundleId);
         Assert.assertEquals(bundleJson.getExternalKey(), externalKey);
         Assert.assertEquals(bundleJson.getSubscriptions().size(), 1);
         Assert.assertEquals(bundleJson.getAuditLogs(), auditLogs);
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 114d0fc..18e2914 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
@@ -33,7 +33,7 @@ public class TestBundleTimelineJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID().toString(),
+        final EventSubscriptionJson event = new EventSubscriptionJson(UUID.randomUUID(),
                                                                       BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                       new LocalDate(),
                                                                       UUID.randomUUID().toString(),
@@ -46,8 +46,8 @@ public class TestBundleTimelineJson extends JaxrsTestSuiteNoDB {
                                                                       UUID.randomUUID().toString(),
                                                                       UUID.randomUUID().toString(),
                                                                       null);
-        final BundleTimelineJson bundleTimelineJson = new BundleTimelineJson(UUID.randomUUID().toString(),
-                                                                             UUID.randomUUID().toString(),
+        final BundleTimelineJson bundleTimelineJson = new BundleTimelineJson(UUID.randomUUID(),
+                                                                             UUID.randomUUID(),
                                                                              UUID.randomUUID().toString(),
                                                                              ImmutableList.<EventSubscriptionJson>of(event),
                                                                              null);
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 422a0f1..265c3e4 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
@@ -36,10 +36,10 @@ public class TestCreditJson extends JaxrsTestSuiteNoDB {
     public void testJson() throws Exception {
         final BigDecimal creditAmount = BigDecimal.TEN;
         final Currency currency = Currency.AED;
-        final String invoiceId = UUID.randomUUID().toString();
+        final UUID invoiceId = UUID.randomUUID();
         final String invoiceNumber = UUID.randomUUID().toString();
         final LocalDate effectiveDate = clock.getUTCToday();
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
         final CreditJson creditJson = new CreditJson(creditAmount, currency.name(), invoiceId, invoiceNumber, effectiveDate,
                                                      accountId, null, auditLogs);
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 36edc38..792a1a2 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
@@ -28,8 +28,8 @@ public class TestCustomFieldJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String customFieldId = UUID.randomUUID().toString();
-        final String objectId = UUID.randomUUID().toString();
+        final UUID customFieldId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
         final ObjectType objectType = ObjectType.INVOICE;
         final String name = UUID.randomUUID().toString();
         final String value = UUID.randomUUID().toString();
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 5bc6273..093e5ca 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
@@ -43,15 +43,15 @@ public class TestEntitlementJsonWithEvents extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String accountId = UUID.randomUUID().toString();
-        final String bundleId = UUID.randomUUID().toString();
-        final String subscriptionId = UUID.randomUUID().toString();
+        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.toString(),
+        final EventSubscriptionJson newEvent = new EventSubscriptionJson(eventId,
                                                                          BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                          effectiveDate.toLocalDate(),
                                                                          UUID.randomUUID().toString(),
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 32a4378..f3a5a34 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
@@ -28,7 +28,7 @@ public class TestInvoiceEmailJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String accountId = UUIDs.randomUUID().toString();
+        final UUID accountId = UUIDs.randomUUID();
         final boolean isNotifiedForInvoices = true;
 
         final InvoiceEmailJson invoiceEmailJson = new InvoiceEmailJson(accountId, isNotifiedForInvoices);
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 f61257d..833b874 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
@@ -35,13 +35,13 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String invoiceItemId = UUID.randomUUID().toString();
-        final String invoiceId = UUID.randomUUID().toString();
-        final String linkedInvoiceItemId = UUID.randomUUID().toString();
-        final String accountId = UUID.randomUUID().toString();
-        final String childAccountId = UUID.randomUUID().toString();
-        final String bundleId = UUID.randomUUID().toString();
-        final String subscriptionId = UUID.randomUUID().toString();
+        final UUID invoiceItemId = UUID.randomUUID();
+        final UUID invoiceId = UUID.randomUUID();
+        final UUID linkedInvoiceItemId = UUID.randomUUID();
+        final UUID accountId = UUID.randomUUID();
+        final UUID childAccountId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
+        final UUID subscriptionId = UUID.randomUUID();
         final String planName = UUID.randomUUID().toString();
         final String phaseName = UUID.randomUUID().toString();
         final String usageName = UUID.randomUUID().toString();
@@ -100,12 +100,12 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         Mockito.when(invoiceItem.getInvoiceItemType()).thenReturn(InvoiceItemType.FIXED);
 
         final InvoiceItemJson invoiceItemJson = new InvoiceItemJson(invoiceItem);
-        Assert.assertEquals(invoiceItemJson.getInvoiceItemId(), invoiceItem.getId().toString());
-        Assert.assertEquals(invoiceItemJson.getInvoiceId(), invoiceItem.getInvoiceId().toString());
-        Assert.assertEquals(invoiceItemJson.getLinkedInvoiceItemId(), invoiceItem.getLinkedItemId().toString());
-        Assert.assertEquals(invoiceItemJson.getAccountId(), invoiceItem.getAccountId().toString());
-        Assert.assertEquals(invoiceItemJson.getBundleId(), invoiceItem.getBundleId().toString());
-        Assert.assertEquals(invoiceItemJson.getSubscriptionId(), invoiceItem.getSubscriptionId().toString());
+        Assert.assertEquals(invoiceItemJson.getInvoiceItemId(), invoiceItem.getId());
+        Assert.assertEquals(invoiceItemJson.getInvoiceId(), invoiceItem.getInvoiceId());
+        Assert.assertEquals(invoiceItemJson.getLinkedInvoiceItemId(), invoiceItem.getLinkedItemId());
+        Assert.assertEquals(invoiceItemJson.getAccountId(), invoiceItem.getAccountId());
+        Assert.assertEquals(invoiceItemJson.getBundleId(), invoiceItem.getBundleId());
+        Assert.assertEquals(invoiceItemJson.getSubscriptionId(), invoiceItem.getSubscriptionId());
         Assert.assertEquals(invoiceItemJson.getPlanName(), invoiceItem.getPlanName());
         Assert.assertEquals(invoiceItemJson.getPhaseName(), invoiceItem.getPhaseName());
         Assert.assertEquals(invoiceItemJson.getUsageName(), invoiceItem.getUsageName());
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 5dc7791..5dcbc4e 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
@@ -41,12 +41,12 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         final BigDecimal amount = BigDecimal.TEN;
         final BigDecimal creditAdj = BigDecimal.ONE;
         final BigDecimal refundAdj = BigDecimal.ONE;
-        final String invoiceId = UUID.randomUUID().toString();
+        final UUID invoiceId = UUID.randomUUID();
         final LocalDate invoiceDate = clock.getUTCToday();
         final LocalDate targetDate = clock.getUTCToday();
         final String invoiceNumber = UUID.randomUUID().toString();
         final BigDecimal balance = BigDecimal.ZERO;
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         final String bundleKeys = UUID.randomUUID().toString();
         final CreditJson creditJson = createCreditJson();
         final List<CreditJson> credits = ImmutableList.<CreditJson>of(creditJson);
@@ -98,12 +98,12 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceJson.getAmount(), invoice.getChargedAmount());
         Assert.assertEquals(invoiceJson.getCreditAdj(), invoice.getCreditedAmount());
         Assert.assertEquals(invoiceJson.getRefundAdj(), invoice.getRefundedAmount());
-        Assert.assertEquals(invoiceJson.getInvoiceId(), invoice.getId().toString());
+        Assert.assertEquals(invoiceJson.getInvoiceId(), invoice.getId());
         Assert.assertEquals(invoiceJson.getInvoiceDate(), invoice.getInvoiceDate());
         Assert.assertEquals(invoiceJson.getTargetDate(), invoice.getTargetDate());
         Assert.assertEquals(invoiceJson.getInvoiceNumber(), String.valueOf(invoice.getInvoiceNumber()));
         Assert.assertEquals(invoiceJson.getBalance(), invoice.getBalance());
-        Assert.assertEquals(invoiceJson.getAccountId(), invoice.getAccountId().toString());
+        Assert.assertEquals(invoiceJson.getAccountId(), invoice.getAccountId());
         Assert.assertEquals(invoiceJson.getBundleKeys(), bundleKeys);
         Assert.assertEquals(invoiceJson.getCredits(), credits);
         Assert.assertNull(invoiceJson.getAuditLogs());
@@ -113,10 +113,10 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
     private CreditJson createCreditJson() {
         final BigDecimal creditAmount = BigDecimal.TEN;
         final Currency currency = Currency.USD;
-        final String invoiceId = UUID.randomUUID().toString();
+        final UUID invoiceId = UUID.randomUUID();
         final String invoiceNumber = UUID.randomUUID().toString();
         final LocalDate effectiveDate = clock.getUTCToday();
-        final String accountId = UUID.randomUUID().toString();
+        final UUID accountId = UUID.randomUUID();
         return new CreditJson(creditAmount, currency.name(), invoiceId, invoiceNumber, effectiveDate,  accountId, null, null);
     }
 }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestSubscriptionUsageRecordJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestSubscriptionUsageRecordJson.java
index 95c232b..7af09df 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestSubscriptionUsageRecordJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestSubscriptionUsageRecordJson.java
@@ -34,7 +34,7 @@ public class TestSubscriptionUsageRecordJson extends JaxrsTestSuiteNoDB {
     @Test(groups = "fast")
     public void testJson() throws Exception {
         final LocalDate localDate = new LocalDate();
-        final String subscriptionId = UUID.randomUUID().toString();
+        final UUID subscriptionId = UUID.randomUUID();
         final String trackingId = UUID.randomUUID().toString();
         final List<UnitUsageRecordJson> unitUsageRecords = new ArrayList<UnitUsageRecordJson>();
         final List<UsageRecordJson> usageRecords = new ArrayList<UsageRecordJson>();
@@ -53,7 +53,7 @@ public class TestSubscriptionUsageRecordJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(subscriptionUsageRecordJson.getUnitUsageRecords().get(0).getUsageRecords().get(0).getRecordDate(), localDate);
 
         final SubscriptionUsageRecord subscriptionUsageRecord = subscriptionUsageRecordJson.toSubscriptionUsageRecord();
-        Assert.assertEquals(subscriptionUsageRecord.getSubscriptionId().toString(), subscriptionId);
+        Assert.assertEquals(subscriptionUsageRecord.getSubscriptionId(), subscriptionId);
         Assert.assertEquals(subscriptionUsageRecord.getTrackingId(), trackingId);
         Assert.assertEquals(subscriptionUsageRecord.getUnitUsageRecord().size(), 1);
         Assert.assertEquals(subscriptionUsageRecord.getUnitUsageRecord().get(0).getUnitType(), "foo");
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 2a6da5e..be48168 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
@@ -30,7 +30,7 @@ public class TestTagDefinitionJson extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final String id = UUID.randomUUID().toString();
+        final UUID id = UUID.randomUUID();
         final Boolean isControlTag = true;
         final String name = UUID.randomUUID().toString();
         final String description = UUID.randomUUID().toString();
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 8217696..252d079 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
@@ -236,7 +236,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), transition.getEffectiveTransitionTime());
+        final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(catalog, transition), subscription.getStartDate());
         return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, internalTenantContext, accountBillCycleDayLocal);
     }
 
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
index fc14f47..2e63123 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
@@ -21,6 +21,8 @@ package org.killbill.billing.overdue.notification;
 import java.util.Iterator;
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.joda.time.DateTime;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.overdue.service.DefaultOverdueService;
@@ -41,6 +43,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public abstract class DefaultOverduePosterBase implements OverduePoster {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultOverduePosterBase.class);
@@ -49,10 +53,10 @@ public abstract class DefaultOverduePosterBase implements OverduePoster {
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
 
     public DefaultOverduePosterBase(final NotificationQueueService notificationQueueService,
-                                    final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+                                    final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                                     final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
         this.notificationQueueService = notificationQueueService;
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     @Override
@@ -61,7 +65,7 @@ public abstract class DefaultOverduePosterBase implements OverduePoster {
             final NotificationQueue overdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
                                                                                                  overdueQueueName);
 
-            transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
                 @Override
                 public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                     // Check if we already have notifications for that key
@@ -89,7 +93,7 @@ public abstract class DefaultOverduePosterBase implements OverduePoster {
         try {
             final NotificationQueue checkOverdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
                                                                                                       overdueQueueName);
-            transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
                 @Override
                 public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                     final Iterable<NotificationEventWithMetadata<T>> futureNotifications = getFutureNotificationsForAccountInTransaction(entitySqlDaoWrapperFactory, checkOverdueQueue,
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java
index 9876898..3189c49 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.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
@@ -18,6 +18,8 @@
 
 package org.killbill.billing.overdue.notification;
 
+import javax.inject.Named;
+
 import org.joda.time.DateTime;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -32,13 +34,15 @@ import org.skife.jdbi.v2.IDBI;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class OverdueAsyncBusPoster extends DefaultOverduePosterBase {
 
     @Inject
     public OverdueAsyncBusPoster(final NotificationQueueService notificationQueueService,
-                                 final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+                                 final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                                  final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        super(notificationQueueService, dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     @Override
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
index 3fc227a..1f30971 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
@@ -20,6 +20,8 @@ package org.killbill.billing.overdue.notification;
 
 import java.util.Iterator;
 
+import javax.inject.Named;
+
 import org.joda.time.DateTime;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -33,13 +35,15 @@ import org.skife.jdbi.v2.IDBI;
 
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class OverdueCheckPoster extends DefaultOverduePosterBase {
 
     @Inject
     public OverdueCheckPoster(final NotificationQueueService notificationQueueService,
-                              final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+                              final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                               final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        super(notificationQueueService, dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     @Override
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java
index ca991a2..8c2a498 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.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
@@ -52,7 +52,7 @@ public class TestDefaultOverdueCheckPoster extends OverdueTestSuiteWithEmbeddedD
     @BeforeMethod(groups = "slow")
     public void beforeMethod() throws Exception {
         super.beforeMethod();
-        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
 
         overdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
                                                                      OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
@@ -89,7 +89,7 @@ public class TestDefaultOverdueCheckPoster extends OverdueTestSuiteWithEmbeddedD
     }
 
     private List<NotificationEventWithMetadata<OverdueCheckNotificationKey>> getNotificationsForOverdueable(final Account account) {
-        return entitySqlDaoTransactionalJdbiWrapper.execute(new EntitySqlDaoTransactionWrapper<List<NotificationEventWithMetadata<OverdueCheckNotificationKey>>>() {
+        return entitySqlDaoTransactionalJdbiWrapper.execute(true, new EntitySqlDaoTransactionWrapper<List<NotificationEventWithMetadata<OverdueCheckNotificationKey>>>() {
             @Override
             public List<NotificationEventWithMetadata<OverdueCheckNotificationKey>> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 // This will go through all results to close the connection
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
index 1256398..7ab31a6 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
@@ -73,6 +74,8 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, PaymentApiException> implements PaymentDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultPaymentDao.class);
@@ -82,9 +85,9 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     private final Clock clock;
 
     @Inject
-    public DefaultPaymentDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+    public DefaultPaymentDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                              final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final PersistentBus eventBus) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), PaymentSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), PaymentSqlDao.class);
         this.paginationHelper = new DefaultPaginationSqlDaoHelper(transactionalSqlDao);
         this.eventBus = eventBus;
         this.clock = clock;
@@ -92,7 +95,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentAttemptModelDao getPaymentAttempt(final UUID attemptId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
             @Override
             public PaymentAttemptModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class).getById(attemptId.toString(), context);
@@ -102,7 +105,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentAttemptModelDao insertPaymentAttemptWithProperties(final PaymentAttemptModelDao attempt, final InternalCallContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
 
             @Override
             public PaymentAttemptModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -114,7 +117,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public void updatePaymentAttempt(final UUID paymentAttemptId, @Nullable final UUID transactionId, final String state, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final String transactionIdStr = transactionId != null ? transactionId.toString() : null;
@@ -127,7 +130,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public void updatePaymentAttemptWithProperties(final UUID paymentAttemptId, final UUID paymentMethodId, final UUID transactionId, final String state, final byte[] pluginProperties, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -148,6 +151,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
                                                   public Long getCount(final PaymentAttemptSqlDao sqlDao, final InternalTenantContext context) {
                                                       return sqlDao.getCountByStateNameAcrossTenants(stateName, createdBefore);
                                                   }
+
                                                   @Override
                                                   public Iterator<PaymentAttemptModelDao> build(final PaymentAttemptSqlDao sqlDao, final Long offset, final Long limit, final Ordering ordering, final InternalTenantContext context) {
                                                       return sqlDao.getByStateNameAcrossTenants(stateName, createdBefore, offset, limit, ordering.toString());
@@ -162,7 +166,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentAttemptModelDao> getPaymentAttempts(final String paymentExternalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentAttemptModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentAttemptModelDao>>() {
 
             @Override
             public List<PaymentAttemptModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -174,7 +178,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentAttemptModelDao> getPaymentAttemptByTransactionExternalKey(final String externalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentAttemptModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentAttemptModelDao>>() {
 
             @Override
             public List<PaymentAttemptModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -211,7 +215,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentTransactionModelDao> getPaymentTransactionsByExternalKey(final String transactionExternalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
             @Override
             public List<PaymentTransactionModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TransactionSqlDao.class).getPaymentTransactionsByExternalKey(transactionExternalKey, context);
@@ -221,7 +225,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentModelDao getPaymentByExternalKey(final String paymentExternalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
             @Override
             public PaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).getPaymentByExternalKey(paymentExternalKey, context);
@@ -291,7 +295,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     public PaymentAndTransactionModelDao insertPaymentWithFirstTransaction(final PaymentModelDao payment, final PaymentTransactionModelDao paymentTransaction, final InternalCallContext context) {
         final PaymentAndTransactionModelDao paymentAndTransactionModelDao = new PaymentAndTransactionModelDao();
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {
 
             @Override
             public PaymentAndTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -310,7 +314,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentTransactionModelDao updatePaymentWithNewTransaction(final UUID paymentId, final PaymentTransactionModelDao paymentTransaction, final InternalCallContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentTransactionModelDao>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<PaymentTransactionModelDao>() {
             @Override
             public PaymentTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TransactionSqlDao transactional = entitySqlDaoWrapperFactory.become(TransactionSqlDao.class);
@@ -361,7 +365,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
                                                                                   final InternalCallContext context) {
         final PaymentAndTransactionModelDao paymentAndTransactionModelDao = new PaymentAndTransactionModelDao();
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {
 
             @Override
             public PaymentAndTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -403,7 +407,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentModelDao getPayment(final UUID paymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
             @Override
             public PaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).getById(paymentId.toString(), context);
@@ -413,7 +417,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentTransactionModelDao getPaymentTransaction(final UUID transactionId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentTransactionModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentTransactionModelDao>() {
             @Override
             public PaymentTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TransactionSqlDao.class).getById(transactionId.toString(), context);
@@ -424,7 +428,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     @Override
     public List<PaymentModelDao> getPaymentsForAccount(final UUID accountId, final InternalTenantContext context) {
         Preconditions.checkArgument(context.getAccountRecordId() != null);
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentModelDao>>() {
             @Override
             public List<PaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).getByAccountRecordId(context);
@@ -434,7 +438,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentModelDao> getPaymentsByStatesAcrossTenants(final String[] states, final DateTime createdBeforeDate, final DateTime createdAfterDate, final int limit) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentModelDao>>() {
             @Override
             public List<PaymentModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).getPaymentsByStatesAcrossTenants(ImmutableList.copyOf(states), createdBeforeDate.toDate(), createdAfterDate.toDate(), limit);
@@ -445,7 +449,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     @Override
     public List<PaymentTransactionModelDao> getTransactionsForAccount(final UUID accountId, final InternalTenantContext context) {
         Preconditions.checkArgument(context.getAccountRecordId() != null);
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
             @Override
             public List<PaymentTransactionModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TransactionSqlDao.class).getByAccountRecordId(context);
@@ -455,7 +459,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentTransactionModelDao> getTransactionsForPayment(final UUID paymentId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentTransactionModelDao>>() {
             @Override
             public List<PaymentTransactionModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TransactionSqlDao.class).getByPaymentId(paymentId, context);
@@ -465,7 +469,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentMethodModelDao insertPaymentMethod(final PaymentMethodModelDao paymentMethod, final InternalCallContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
             @Override
             public PaymentMethodModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return insertPaymentMethodInTransaction(entitySqlDaoWrapperFactory, paymentMethod, context);
@@ -481,7 +485,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
             @Override
             public PaymentMethodModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getById(paymentMethodId.toString(), context);
@@ -491,7 +495,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentMethodModelDao getPaymentMethodByExternalKey(final String paymentMethodExternalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
             @Override
             public PaymentMethodModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getByExternalKey(paymentMethodExternalKey, context);
@@ -501,7 +505,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentMethodModelDao getPaymentMethodIncludedDeleted(final UUID paymentMethodId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
             @Override
             public PaymentMethodModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getPaymentMethodIncludedDelete(paymentMethodId.toString(), context);
@@ -511,7 +515,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public PaymentMethodModelDao getPaymentMethodByExternalKeyIncludedDeleted(final String paymentMethodExternalKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<PaymentMethodModelDao>() {
             @Override
             public PaymentMethodModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getPaymentMethodByExternalKeyIncludedDeleted(paymentMethodExternalKey, context);
@@ -521,7 +525,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentMethodModelDao> getPaymentMethods(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
             @Override
             public List<PaymentMethodModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getForAccount(context);
@@ -530,7 +534,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     }
 
     public List<PaymentMethodModelDao> getPaymentMethodsIncludedDeleted(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
             @Override
             public List<PaymentMethodModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(PaymentMethodSqlDao.class).getForAccountIncludedDelete(context);
@@ -538,7 +542,6 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
         });
     }
 
-
     @Override
     public Pagination<PaymentMethodModelDao> searchPaymentMethods(final String searchKey, final Long offset, final Long limit, final InternalTenantContext context) {
         return paginationHelper.getPagination(PaymentMethodSqlDao.class,
@@ -580,7 +583,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public void deletedPaymentMethod(final UUID paymentMethodId, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 deletedPaymentMethodInTransaction(entitySqlDaoWrapperFactory, paymentMethodId, context);
@@ -600,7 +603,7 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
 
     @Override
     public List<PaymentMethodModelDao> refreshPaymentMethods(final String pluginName, final List<PaymentMethodModelDao> newPaymentMethods, final InternalCallContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
+        return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<List<PaymentMethodModelDao>>() {
 
             @Override
             public List<PaymentMethodModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index b3a7d19..c1933c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.141.40</version>
+        <version>0.141.43</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.19.6-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/CleanupListener.java b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/CleanupListener.java
index d393cb8..813f705 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/CleanupListener.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/CleanupListener.java
@@ -28,6 +28,7 @@ import javax.servlet.ServletContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ch.qos.logback.classic.LoggerContext;
 import net.sf.log4jdbc.sql.jdbcapi.DriverSpy;
 
 public class CleanupListener implements ServletContextListener {
@@ -76,5 +77,9 @@ public class CleanupListener implements ServletContextListener {
                 logger.warn("Unable to de-register driver", e);
             }
         }
+
+//         avoid memory leaks: https://logback.qos.ch/manual/jmxConfig.html
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        lc.stop();
     }
 }
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillJdbcTenantRealmProvider.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillJdbcTenantRealmProvider.java
index 5774818..4e7ca1c 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillJdbcTenantRealmProvider.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillJdbcTenantRealmProvider.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -27,6 +27,8 @@ import org.killbill.billing.util.config.definition.SecurityConfig;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import static org.killbill.billing.platform.glue.KillBillPlatformModuleBase.SHIRO_DATA_SOURCE_ID;
+
 public class KillbillJdbcTenantRealmProvider implements Provider<KillbillJdbcTenantRealm> {
 
     private final SecurityConfig securityConfig;
@@ -34,7 +36,7 @@ public class KillbillJdbcTenantRealmProvider implements Provider<KillbillJdbcTen
     private final DataSource dataSource;
 
     @Inject
-    public KillbillJdbcTenantRealmProvider(final SecurityConfig securityConfig, final CacheManager cacheManager, @Named(KillbillPlatformModule.SHIRO_DATA_SOURCE_ID_NAMED) final DataSource dataSource) {
+    public KillbillJdbcTenantRealmProvider(final SecurityConfig securityConfig, final CacheManager cacheManager, @Named(SHIRO_DATA_SOURCE_ID) final DataSource dataSource) {
         this.securityConfig = securityConfig;
         this.cacheManager = cacheManager;
         this.dataSource = dataSource;
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
index b182e9e..6ffbc2a 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
@@ -99,7 +99,6 @@ import com.google.inject.name.Names;
 
 public class KillbillServerModule extends KillbillPlatformModule {
 
-    public static final String SHIRO_DATA_SOURCE_ID = "shiro";
     public static final String STATIC_CONFIG = "StaticConfig";
 
     public KillbillServerModule(final ServletContext servletContext, final KillbillServerConfig serverConfig, final KillbillConfigSource configSource) {
@@ -139,7 +138,14 @@ public class KillbillServerModule extends KillbillPlatformModule {
 
         // Same database, but different pool: clone the object so the shutdown sequence cleans the pool properly
         shiroEmbeddedDB = new KillBillEmbeddedDBProvider(daoConfig).get();
-        bind(EmbeddedDB.class).annotatedWith(Names.named(SHIRO_DATA_SOURCE_ID_NAMED)).toInstance(shiroEmbeddedDB);
+        bind(EmbeddedDB.class).annotatedWith(Names.named(SHIRO_DATA_SOURCE_ID)).toInstance(shiroEmbeddedDB);
+
+        if (mainRoDataSourceConfig.isEnabled()) {
+            mainRoEmbeddedDB = new KillBillEmbeddedDBProvider(mainRoDataSourceConfig).get();
+        } else {
+            mainRoEmbeddedDB = mainEmbeddedDB;
+        }
+        bind(EmbeddedDB.class).annotatedWith(Names.named(MAIN_RO_DATA_SOURCE_ID)).toInstance(mainRoEmbeddedDB);
     }
 
     @Override
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
index b9cb18c..abb1544 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
@@ -160,9 +160,9 @@ public class PushNotificationListener {
     public void resendPushNotification(final PushNotificationKey key) throws JsonProcessingException {
 
         final NotificationJson notification = new NotificationJson(key.getEventType() != null ? key.getEventType().toString() : null,
-                                                                   key.getAccountId() != null ? key.getAccountId().toString() : null,
+                                                                   key.getAccountId(),
                                                                    key.getObjectType() != null ? key.getObjectType().toString() : null,
-                                                                   key.getObjectId() != null ? key.getObjectId().toString() : null,
+                                                                   key.getObjectId(),
                                                                    key.getMetaData());
         final String body = mapper.writeValueAsString(notification);
         doPost(key.getTenantId(), key.getUrl(), body, notification, TIMEOUT_NOTIFICATION, key.getAttemptNumber());
@@ -170,10 +170,10 @@ public class PushNotificationListener {
 
     private void saveRetryPushNotificationInQueue(final UUID tenantId, final String url, final NotificationJson notificationJson, final int attemptRetryNumber) {
         final PushNotificationKey key = new PushNotificationKey(tenantId,
-                                                                notificationJson.getAccountId() != null ? UUID.fromString(notificationJson.getAccountId()) : null,
+                                                                notificationJson.getAccountId(),
                                                                 notificationJson.getEventType(),
                                                                 notificationJson.getObjectType(),
-                                                                notificationJson.getObjectId() != null ? UUID.fromString(notificationJson.getObjectId()) : null,
+                                                                notificationJson.getObjectId(),
                                                                 attemptRetryNumber + 1,
                                                                 notificationJson.getMetaData(),
                                                                 url);
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
index 7b460c0..50b1138 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
@@ -37,6 +37,7 @@ import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
 import org.apache.shiro.realm.Realm;
 import org.killbill.billing.jaxrs.resources.JaxrsResource;
+import org.killbill.billing.jaxrs.resources.KillBillApiDefinition;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.server.listeners.KillbillGuiceListener;
 import org.killbill.billing.tenant.api.Tenant;
@@ -128,66 +129,23 @@ public class TenantFilter implements Filter {
 
     private boolean shouldContinueIfTenantInformationIsWrongOrMissing(final ServletRequest request) {
         boolean shouldContinue = false;
-
         if (request instanceof HttpServletRequest) {
             final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
             final String path = httpServletRequest.getPathInfo();
             final String httpMethod = httpServletRequest.getMethod();
-            if (    // Chicken - egg problem
-                    isTenantCreationRequest(path, httpMethod) ||
-                    // Retrieve user permissions should not require tenant info since this is cross tenants
-                    isPermissionRequest(path) ||
-                    // Node request are cross tenant
-                    isNodeInfoRequest(path) ||
-                    // Metrics servlets
-                    isMetricsRequest(path, httpMethod) ||
-                    // See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
-                    isOptionsRequest(httpMethod) ||
-                    // Shift the responsibility to the plugin
-                    isPluginRequest(path) ||
-                    // Static resources (welcome screen, Swagger, etc.)
-                    isNotKbNorPluginResourceRequest(path, httpMethod)
-                    ) {
-                shouldContinue = true;
-            }
+            shouldContinue = shouldContinueIfTenantInformationIsWrongOrMissing(path, httpMethod);
         }
-
         return shouldContinue;
     }
 
-
-
-    private boolean isPermissionRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.SECURITY_PATH);
-    }
-
-    private boolean isTenantCreationRequest(final String path, final String httpMethod) {
-        return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equals(httpMethod);
-    }
-
-    private boolean isNodeInfoRequest(final String path) {
-        return JaxrsResource.NODES_INFO_PATH.equals(path);
+    private static boolean isMetricsRequest(final String path, final String httpMethod) {
+        return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equalsIgnoreCase(httpMethod);
     }
 
-    private boolean isMetricsRequest(final String path, final String httpMethod) {
-        return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equals(httpMethod);
-    }
-
-    private boolean isOptionsRequest(final String httpMethod) {
-        return "OPTIONS".equals(httpMethod);
-    }
-
-
-    private boolean isNotKbNorPluginResourceRequest(final String path, final String httpMethod) {
-        return !isPluginRequest(path) && !isKbApiRequest(path) && "GET".equals(httpMethod);
-    }
-
-    private boolean isKbApiRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.PREFIX);
-    }
 
-    private boolean isPluginRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.PLUGINS_PATH);
+    public static boolean shouldContinueIfTenantInformationIsWrongOrMissing(final String path, final String httpMethod) {
+        final boolean requiresTenantInfo = KillBillApiDefinition.requiresTenantInformation(path, httpMethod);
+        return isMetricsRequest(path, httpMethod) || !requiresTenantInfo;
     }
 
     private void sendAuthError(final ServletResponse response, final String errorMessage) throws IOException {
diff --git a/profiles/killbill/src/main/resources/logback.xml b/profiles/killbill/src/main/resources/logback.xml
index c2c710a..1d267cb 100644
--- a/profiles/killbill/src/main/resources/logback.xml
+++ b/profiles/killbill/src/main/resources/logback.xml
@@ -17,12 +17,13 @@
   -->
 
 <configuration>
+    <jmxConfigurator />
     <conversionRule conversionWord="maskedMsg" converterClass="org.killbill.billing.server.log.obfuscators.ObfuscatorConverter" />
 
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
             <!-- See http://jira.qos.ch/browse/LOGBACK-262 -->
-            <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+            <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
         </encoder>
     </appender>
 
@@ -43,7 +44,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -64,7 +65,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -85,7 +86,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -106,7 +107,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -127,7 +128,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -148,7 +149,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
index 17cae7a..5d08db5 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
@@ -112,10 +112,10 @@ public class TestPushNotification extends TestJaxrsBase {
         return (remainingMs > 0);
     }
 
-    public void retrieveAccountWithAsserts(final String accountId) {
+    public void retrieveAccountWithAsserts(final UUID accountId) {
         try {
             // Just check we can retrieve the account with the id from the callback
-            killBillClient.getAccount(UUID.fromString(accountId), requestOptions);
+            killBillClient.getAccount(accountId, requestOptions);
         } catch (final Exception e) {
             Assert.fail(e.getMessage());
         }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java
index b5b51ce..39b1b13 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.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
@@ -51,7 +51,7 @@ public class TestKillbillJdbcTenantRealm extends TestJaxrsBase {
         super.beforeMethod();
 
         // Create the tenant
-        final DefaultTenantDao tenantDao = new DefaultTenantDao(dbi, clock, cacheControllerDispatcher, new DefaultNonEntityDao(dbi), Mockito.mock(InternalCallContextFactory.class), securityConfig);
+        final DefaultTenantDao tenantDao = new DefaultTenantDao(dbi, roDbi, clock, cacheControllerDispatcher, new DefaultNonEntityDao(dbi), Mockito.mock(InternalCallContextFactory.class), securityConfig);
         tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
                                    UUID.randomUUID().toString(), UUID.randomUUID().toString());
         tenantDao.create(new TenantModelDao(tenant), internalCallContext);
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 fab57eb..20616d9 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
@@ -737,7 +737,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                             final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
                             final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getName(),
                                                                                    subscriptionForCancellation.getCurrentPhase().getPhaseType());
-                            policy = catalog.planCancelPolicy(spec, utcNow);
+                            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);
@@ -791,7 +791,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
         try {
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
-            final BillingAlignment alignment = catalog.billingAlignment(planPhaseSpecifier, effectiveDate);
+            final BillingAlignment alignment = catalog.billingAlignment(planPhaseSpecifier, subscription.getStartDate());
             return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, context, accountBillCycleDayLocal);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
index 30d18ba..75513df 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -692,12 +692,29 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
 
         transitions = new LinkedList<SubscriptionBaseTransition>();
 
+        // DefaultSubscriptionDao#buildBundleSubscriptions may have added an out-of-order cancellation event (https://github.com/killbill/killbill/issues/897)
+        final SubscriptionBaseEvent cancellationEvent = Iterables.tryFind(inputEvents,
+                                                                          new Predicate<SubscriptionBaseEvent>() {
+                                                                              @Override
+                                                                              public boolean apply(final SubscriptionBaseEvent input) {
+                                                                                  return input.getType() == EventType.API_USER && ((ApiEvent) input).getApiEventType() == ApiEventType.CANCEL;
+                                                                              }
+                                                                          }).orNull();
         for (final SubscriptionBaseEvent cur : inputEvents) {
-
             if (!cur.isActive()) {
                 continue;
             }
 
+            if (cancellationEvent != null) {
+                if (cur.getId().compareTo(cancellationEvent.getId()) == 0) {
+                    // Keep the cancellation event
+                } else if (cur.getType() == EventType.API_USER && (((ApiEvent) cur).getApiEventType() == ApiEventType.TRANSFER || ((ApiEvent) cur).getApiEventType() == ApiEventType.CREATE)) {
+                    // Keep the initial event (SOT use-case)
+                } else if (cur.getEffectiveDate().compareTo(cancellationEvent.getEffectiveDate()) >= 0) {
+                    // Event to ignore past cancellation date
+                    continue;
+                }
+            }
 
             ApiEventType apiEventType = null;
             boolean isFromDisk = true;
@@ -809,7 +826,14 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
             public int compare(final SubscriptionBaseEvent o1, final SubscriptionBaseEvent o2) {
                 int res = o1.getEffectiveDate().compareTo(o2.getEffectiveDate());
                 if (res == 0) {
-                    res = o1.getTotalOrdering() < (o2.getTotalOrdering()) ? -1 : 1;
+                    // In-memory events have a total order of 0, make sure they are after on disk event
+                    if (o1.getTotalOrdering() == 0 && o2.getTotalOrdering() > 0) {
+                        return 1;
+                    } else if (o1.getTotalOrdering() > 0 && o2.getTotalOrdering() == 0) {
+                        return -1;
+                    } else {
+                        res = o1.getTotalOrdering() < (o2.getTotalOrdering()) ? -1 : 1;
+                    }
                 }
                 return res;
             }
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 07a5515..7437681 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
@@ -185,7 +185,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, now);
+            final BillingActionPolicy policy = fullCatalog.planCancelPolicy(planPhase, subscription.getStartDate());
 
             Preconditions.checkState(policy != BillingActionPolicy.START_OF_TERM, "A default START_OF_TERM policy is not availaible");
 
@@ -239,7 +239,7 @@ 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()), clock.getUTCNow()));
+                final BillingAlignment billingAlignment = (subscription.getState() == EntitlementState.PENDING ? null : catalog.billingAlignment(new PlanPhaseSpecifier(subscription.getLastActivePlan().getName(), subscription.getLastActivePhase().getPhaseType()), subscription.getStartDate()));
                 final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, billingAlignment, accountBillCycleDayLocal, context);
                 subscriptionsWithEffectiveDate.put(subscription, effectiveDate);
             }
@@ -404,7 +404,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, effectiveDate);
+            planChangeResult = catalogInternalApi.getFullCatalog(true, true, internalCallContext).planChange(fromPlanPhase, toPlanPhase, subscription.getStartDate());
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
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 c56df6e..cada68b 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
@@ -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
@@ -34,6 +34,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
@@ -113,6 +114,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Multimap;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleModelDao, SubscriptionBaseBundle, SubscriptionApiException> implements SubscriptionDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionDao.class);
@@ -123,11 +126,11 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     private final PersistentBus eventBus;
 
     @Inject
-    public DefaultSubscriptionDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
+    public DefaultSubscriptionDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final AddonUtils addonUtils,
                                   final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
                                   final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao,
                                   final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BundleSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BundleSqlDao.class);
         this.clock = clock;
         this.notificationQueueService = notificationQueueService;
         this.addonUtils = addonUtils;
@@ -141,7 +144,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public SubscriptionBaseBundle getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
             @Override
             public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionBundleModelDao input = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesFromAccountAndKey(accountId.toString(), bundleKey, context);
@@ -152,7 +155,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public List<SubscriptionBaseBundle> getSubscriptionBundleForAccount(final UUID accountId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
             @Override
             public List<SubscriptionBaseBundle> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionBundleModelDao> models = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundleFromAccount(accountId.toString(), context);
@@ -169,7 +172,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public SubscriptionBaseBundle getSubscriptionBundleFromId(final UUID bundleId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
             @Override
             public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionBundleModelDao model = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getById(bundleId.toString(), context);
@@ -181,7 +184,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     @Override
     public List<SubscriptionBaseBundle> getSubscriptionBundlesForKey(final String bundleKey, final InternalTenantContext context) {
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
             @Override
             public List<SubscriptionBaseBundle> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionBundleModelDao> models = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForLikeKey(bundleKey, context);
@@ -216,7 +219,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public Iterable<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Iterable<UUID>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Iterable<UUID>>() {
             @Override
             public Iterable<UUID> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -255,8 +258,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     @Override
     public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
 
-
-        return transactionalSqlDao.execute(SubscriptionBaseApiException.class, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
+        return transactionalSqlDao.execute(false, SubscriptionBaseApiException.class, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
 
             //
             // Because the creation of the SubscriptionBundle is not atomic (with creation of Subscription/SubscriptionEvent), we verify if we were left
@@ -280,19 +282,18 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                 if (existingBundleForAccount != null) {
                     final List<SubscriptionModelDao> accountSubscriptions = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getByAccountRecordId(context);
                     if (accountSubscriptions == null ||
-                        ! Iterables.any(accountSubscriptions, new Predicate<SubscriptionModelDao>() {
-                        @Override
-                        public boolean apply(final SubscriptionModelDao input) {
-                            return input.getBundleId().equals(existingBundleForAccount.getId());
-                        }
-                    })) {
+                        !Iterables.any(accountSubscriptions, new Predicate<SubscriptionModelDao>() {
+                            @Override
+                            public boolean apply(final SubscriptionModelDao input) {
+                                return input.getBundleId().equals(existingBundleForAccount.getId());
+                            }
+                        })) {
                         return SubscriptionBundleModelDao.toSubscriptionBundle(existingBundleForAccount);
                     }
                 }
                 return null;
             }
 
-
             @Override
             public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionBundleModelDao> existingBundles = bundle.getExternalKey() == null ? ImmutableList.<SubscriptionBundleModelDao>of()
@@ -344,7 +345,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     @Override
     public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId, final InternalTenantContext context) {
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<UUID>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<UUID>() {
             @Override
             public UUID inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionModelDao subscriptionModel = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getById(subscriptionId.toString(), context);
@@ -376,7 +377,7 @@ 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(new EntitySqlDaoTransactionWrapper<SubscriptionBase>() {
+        final SubscriptionBase shellSubscription = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<SubscriptionBase>() {
             @Override
             public SubscriptionBase inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionModelDao subscriptionModel = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getById(subscriptionId.toString(), context);
@@ -393,7 +394,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     private List<SubscriptionBase> getSubscriptionFromBundleId(final UUID bundleId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
             @Override
             public List<SubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -439,7 +440,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     private Map<UUID, List<SubscriptionBase>> getSubscriptionsFromAccountId(final InternalTenantContext context) {
-        final List<SubscriptionBase> allSubscriptions = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
+        final List<SubscriptionBase> allSubscriptions = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
             @Override
             public List<SubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -477,7 +478,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         final Date ctd = (subscription.getChargedThroughDate() != null) ? subscription.getChargedThroughDate().toDate() : null;
         final InternalCallContext contextWithUpdatedDate = contextWithUpdatedDate(context);
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionSqlDao transactionalDao = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
@@ -493,7 +494,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void createNextPhaseEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent readyPhaseEvent, final SubscriptionBaseEvent nextPhaseEvent, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
@@ -515,7 +516,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public SubscriptionBaseEvent getEventById(final UUID eventId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseEvent>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<SubscriptionBaseEvent>() {
             @Override
             public SubscriptionBaseEvent inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionEventModelDao model = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getById(eventId.toString(), context);
@@ -526,7 +527,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public List<SubscriptionBaseEvent> getEventsForSubscription(final UUID subscriptionId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
             @Override
             public List<SubscriptionBaseEvent> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionEventModelDao> models = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getActiveEventsForSubscription(subscriptionId.toString(), context);
@@ -539,7 +540,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     public List<SubscriptionBaseEvent> getPendingEventsForSubscription(final UUID subscriptionId, final InternalTenantContext context) {
         final Date now = clock.getUTCNow().toDate();
 
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
             @Override
             public List<SubscriptionBaseEvent> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionEventModelDao> eventModels = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getFutureActiveEventForSubscription(subscriptionId.toString(), now, context);
@@ -555,7 +556,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void createSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionBaseEvent> initialEvents, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
@@ -580,7 +581,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void createSubscriptionsWithAddOns(final List<SubscriptionBaseWithAddOns> subscriptions, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
@@ -613,7 +614,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void cancelSubscriptionsOnBasePlanEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent event, final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionBaseEvent> cancelEvents, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 cancelSubscriptionsFromTransaction(entitySqlDaoWrapperFactory, subscriptions, cancelEvents, catalog, context);
@@ -626,7 +627,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void notifyOnBasePlanEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent event, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 notifyBusOfEffectiveImmediateChange(entitySqlDaoWrapperFactory, subscription, event, 0, context);
@@ -638,7 +639,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void cancelSubscriptions(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionBaseEvent> cancelEvents, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 cancelSubscriptionsFromTransaction(entitySqlDaoWrapperFactory, subscriptions, cancelEvents, catalog, context);
@@ -662,14 +663,13 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void undoChangePlan(final DefaultSubscriptionBase subscription, final List<SubscriptionBaseEvent> undoChangePlanEvents, final InternalCallContext context) {
-            undoOperation(subscription, undoChangePlanEvents, ApiEventType.CHANGE, SubscriptionBaseTransitionType.UNDO_CHANGE, context);
+        undoOperation(subscription, undoChangePlanEvents, ApiEventType.CHANGE, SubscriptionBaseTransitionType.UNDO_CHANGE, context);
     }
 
-
     private void undoOperation(final DefaultSubscriptionBase subscription, final List<SubscriptionBaseEvent> inputEvents, final ApiEventType targetOperation, final SubscriptionBaseTransitionType transitionType, final InternalCallContext context) {
 
         final InternalCallContext contextWithUpdatedDate = contextWithUpdatedDate(context);
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
@@ -718,7 +718,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                                  ((ApiEvent) inputChangeEvent).getApiEventType() == ApiEventType.CHANGE);
         Preconditions.checkState(inputChangeEvent.getSubscriptionId().equals(subscription.getId()));
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -779,12 +779,11 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         });
     }
 
-
     private List<SubscriptionBaseEvent> filterSubscriptionBaseEvents(final Collection<SubscriptionEventModelDao> models) {
         final Collection<SubscriptionEventModelDao> filteredModels = Collections2.filter(models, new Predicate<SubscriptionEventModelDao>() {
             @Override
             public boolean apply(@Nullable final SubscriptionEventModelDao input) {
-                return input.getUserType() != ApiEventType.UNCANCEL && input.getUserType() != ApiEventType.UNDO_CHANGE ;
+                return input.getUserType() != ApiEventType.UNCANCEL && input.getUserType() != ApiEventType.UNDO_CHANGE;
             }
         });
         return new ArrayList<SubscriptionBaseEvent>(Collections2.transform(filteredModels, new Function<SubscriptionEventModelDao, SubscriptionBaseEvent>() {
@@ -796,7 +795,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     private List<SubscriptionBaseEvent> getEventsForAccountId(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
             @Override
             public List<SubscriptionBaseEvent> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<SubscriptionEventModelDao> models = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getByAccountRecordId(context);
@@ -1038,9 +1037,9 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void transfer(final UUID srcAccountId, final UUID destAccountId, final BundleTransferData bundleTransferData,
-                         final List<TransferCancelData> transferCancelData,  final Catalog catalog, final InternalCallContext fromContext, final InternalCallContext toContext) {
+                         final List<TransferCancelData> transferCancelData, final Catalog catalog, final InternalCallContext fromContext, final InternalCallContext toContext) {
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -1049,7 +1048,6 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                     cancelSubscriptionFromTransaction(cancel.getSubscription(), cancel.getCancelEvent(), entitySqlDaoWrapperFactory, catalog, fromContext, 0);
                 }
 
-
                 // Rename externalKey from source bundle
                 final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
                 bundleSqlDao.renameBundleExternalKey(bundleTransferData.getData().getExternalKey(), "tsf", fromContext);
@@ -1063,7 +1061,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void updateBundleExternalKey(final UUID bundleId, final String externalKey, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
 
@@ -1076,7 +1074,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
     @Override
     public void createBCDChangeEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent bcdEvent, final Catalog catalog, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
@@ -1226,7 +1224,6 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         return subscriptionWithNewEvent;
     }
 
-
     private InternalCallContext contextWithUpdatedDate(final InternalCallContext input) {
         return new InternalCallContext(input, clock.getUTCNow());
     }
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
new file mode 100644
index 0000000..9dff853
--- /dev/null
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestDefaultSubscriptionBase.java
@@ -0,0 +1,131 @@
+/*
+ * 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.user;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
+import org.killbill.billing.subscription.SubscriptionTestSuiteNoDB;
+import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
+import org.killbill.billing.subscription.events.phase.PhaseEventBuilder;
+import org.killbill.billing.subscription.events.phase.PhaseEventData;
+import org.killbill.billing.subscription.events.user.ApiEventBuilder;
+import org.killbill.billing.subscription.events.user.ApiEventCancel;
+import org.killbill.billing.subscription.events.user.ApiEventCreate;
+import org.killbill.billing.subscription.events.user.ApiEventType;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static org.killbill.billing.subscription.events.user.ApiEventType.CREATE;
+
+public class TestDefaultSubscriptionBase extends SubscriptionTestSuiteNoDB {
+
+    @Test(groups = "fast")
+    public void testCancelSOT() throws Exception {
+        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder());
+
+        final UUID subscriptionId = UUID.randomUUID();
+        final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
+        inputEvents.add(new ApiEventCreate(new ApiEventBuilder().setApiEventType(CREATE)
+                                                                .setEventPlan("laser-scope-monthly")
+                                                                .setEventPlanPhase("laser-scope-monthly-discount")
+                                                                .setEventPriceList("DEFAULT")
+                                                                .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))
+                                                                .setTotalOrdering(3)
+                                                                .setActive(true)));
+        inputEvents.add(new ApiEventCancel(new ApiEventBuilder().setApiEventType(ApiEventType.CANCEL)
+                                                                .setEventPlan(null)
+                                                                .setEventPlanPhase(null)
+                                                                .setEventPriceList(null)
+                                                                .setFromDisk(false)
+                                                                .setUuid(UUID.randomUUID())
+                                                                .setSubscriptionId(subscriptionId)
+                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setUpdatedDate(null)
+                                                                .setEffectiveDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setTotalOrdering(0) // In-memory event
+                                                                .setActive(true)));
+        subscriptionBase.rebuildTransitions(inputEvents, catalog);
+
+        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(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));
+    }
+
+    @Test(groups = "fast", description = "https://github.com/killbill/killbill/issues/897")
+    public void testFutureCancelBeforePhase() throws Exception {
+        final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder());
+
+        final UUID subscriptionId = UUID.randomUUID();
+        final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
+        inputEvents.add(new ApiEventCreate(new ApiEventBuilder().setApiEventType(CREATE)
+                                                                .setEventPlan("laser-scope-monthly")
+                                                                .setEventPlanPhase("laser-scope-monthly-discount")
+                                                                .setEventPriceList("DEFAULT")
+                                                                .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))
+                                                                .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))
+                                                                  .setEffectiveDate(new DateTime(2012, 6, 1, 0, 0, DateTimeZone.UTC))
+                                                                  .setTotalOrdering(4)
+                                                                  .setActive(true)));
+        inputEvents.add(new ApiEventCancel(new ApiEventBuilder().setApiEventType(ApiEventType.CANCEL)
+                                                                .setEventPlan(null)
+                                                                .setEventPlanPhase(null)
+                                                                .setEventPriceList(null)
+                                                                .setFromDisk(false)
+                                                                .setUuid(UUID.randomUUID())
+                                                                .setSubscriptionId(subscriptionId)
+                                                                .setCreatedDate(new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setUpdatedDate(null)
+                                                                .setEffectiveDate(new DateTime(2012, 6, 1, 0, 0, DateTimeZone.UTC))
+                                                                .setTotalOrdering(0) // In-memory event
+                                                                .setActive(true)));
+        subscriptionBase.rebuildTransitions(inputEvents, catalog);
+
+        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(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/engine/dao/MockSubscriptionDaoSql.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java
index 790ef04..3727c08 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.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
@@ -18,26 +18,27 @@
 
 package org.killbill.billing.subscription.engine.dao;
 
-import org.killbill.billing.catalog.api.CatalogInternalApi;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.skife.jdbi.v2.IDBI;
+import javax.inject.Named;
 
-import org.killbill.bus.api.PersistentBus;
-import org.killbill.billing.catalog.api.CatalogService;
-import org.killbill.clock.Clock;
-import org.killbill.notificationq.api.NotificationQueueService;
 import org.killbill.billing.subscription.engine.addon.AddonUtils;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.bus.api.PersistentBus;
+import org.killbill.clock.Clock;
+import org.killbill.notificationq.api.NotificationQueueService;
+import org.skife.jdbi.v2.IDBI;
 
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class MockSubscriptionDaoSql extends DefaultSubscriptionDao {
 
     @Inject
-    public MockSubscriptionDaoSql(final IDBI dbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
+    public MockSubscriptionDaoSql(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
                                   final PersistentBus eventBus, final CacheControllerDispatcher cacheControllerDispatcher,
                                   final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(dbi, clock, addonUtils, notificationQueueService, eventBus,  cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+        super(dbi, roDbi, clock, addonUtils, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 }
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
index 5fa4996..30ef282 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -20,6 +20,7 @@ package org.killbill.billing.tenant.dao;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.tenant.api.TenantApiException;
@@ -32,12 +33,14 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper
 import org.killbill.clock.Clock;
 import org.skife.jdbi.v2.IDBI;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultTenantBroadcastDao extends EntityDaoBase<TenantBroadcastModelDao, Entity, TenantApiException> implements TenantBroadcastDao {
 
     @Inject
-    public DefaultTenantBroadcastDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+    public DefaultTenantBroadcastDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                                      final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantBroadcastSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantBroadcastSqlDao.class);
     }
 
     @Override
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
index 18f2238..8be495c 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.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
@@ -21,6 +21,8 @@ package org.killbill.billing.tenant.dao;
 import java.util.List;
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.SimpleAuthenticationInfo;
 import org.apache.shiro.codec.Base64;
@@ -56,6 +58,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, TenantApiException> implements TenantDao {
 
     private final RandomNumberGenerator rng = new SecureRandomNumberGenerator();
@@ -63,9 +67,9 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
     private final SecurityConfig securityConfig;
 
     @Inject
-    public DefaultTenantDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+    public DefaultTenantDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                             final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final SecurityConfig securityConfig) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantSqlDao.class);
         this.securityConfig = securityConfig;
     }
 
@@ -76,7 +80,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public TenantModelDao getTenantByApiKey(final String apiKey) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
             @Override
             public TenantModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantSqlDao.class).getByApiKey(apiKey);
@@ -92,7 +96,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
         final String hashedPasswordBase64 = new SimpleHash(KillbillCredentialsMatcher.HASH_ALGORITHM_NAME,
                                                            entity.getApiSecret(), salt, securityConfig.getShiroNbHashIterations()).toBase64();
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TenantModelDao tenantModelDaoWithSecret = new TenantModelDao(entity.getId(), context.getCreatedDate(), context.getUpdatedDate(),
@@ -107,7 +111,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @VisibleForTesting
     AuthenticationInfo getAuthenticationInfoForTenant(final UUID id) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AuthenticationInfo>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<AuthenticationInfo>() {
             @Override
             public AuthenticationInfo inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TenantModelDao tenantModelDao = entitySqlDaoWrapperFactory.become(TenantSqlDao.class).getSecrets(id.toString());
@@ -122,7 +126,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public List<String> getTenantValueForKey(final String key, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<String>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<String>>() {
             @Override
             public List<String> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<TenantKVModelDao> tenantKV = entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class).getTenantValueForKey(key, context);
@@ -138,7 +142,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public void addTenantKeyValue(final String key, final String value, final boolean uniqueKey, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TenantKVModelDao tenantKVModelDao = new TenantKVModelDao(UUIDs.randomUUID(), context.getCreatedDate(), context.getUpdatedDate(), key, value);
@@ -155,7 +159,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public void updateTenantLastKeyValue(final String key, final String value, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TenantKVModelDao tenantKVModelDao = new TenantKVModelDao(UUIDs.randomUUID(), context.getCreatedDate(), context.getUpdatedDate(), key, value);
@@ -181,7 +185,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public void deleteTenantKey(final String key, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 deleteFromTransaction(key, entitySqlDaoWrapperFactory, context);
@@ -193,7 +197,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public TenantKVModelDao getKeyByRecordId(final Long recordId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantKVModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantKVModelDao>() {
             @Override
             public TenantKVModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class).getByRecordId(recordId, context);
@@ -203,7 +207,7 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
 
     @Override
     public List<TenantKVModelDao> searchTenantKeyValues(final String searchKeyPrefix, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TenantKVModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TenantKVModelDao>>() {
             @Override
             public List<TenantKVModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class).searchTenantKeyValues(String.format("%s%%", searchKeyPrefix), context);
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
index eef661e..663cb60 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -37,11 +37,13 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import org.killbill.clock.Clock;
 import org.skife.jdbi.v2.IDBI;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class NoCachingTenantBroadcastDao extends EntityDaoBase<TenantBroadcastModelDao, Entity, TenantApiException> implements TenantBroadcastDao {
 
     @Inject
-    public NoCachingTenantBroadcastDao(final IDBI dbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null, internalCallContextFactory), TenantBroadcastSqlDao.class);
+    public NoCachingTenantBroadcastDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, null, null, internalCallContextFactory), TenantBroadcastSqlDao.class);
     }
 
     @Override
@@ -91,7 +93,7 @@ public class NoCachingTenantBroadcastDao extends EntityDaoBase<TenantBroadcastMo
 
     @Override
     public List<TenantBroadcastModelDao> getLatestEntriesFrom(final Long recordId) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TenantBroadcastModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TenantBroadcastModelDao>>() {
             @Override
             public List<TenantBroadcastModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantBroadcastSqlDao.class).getLatestEntries(recordId);
@@ -101,7 +103,7 @@ public class NoCachingTenantBroadcastDao extends EntityDaoBase<TenantBroadcastMo
 
     @Override
     public TenantBroadcastModelDao getLatestEntry() {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantBroadcastModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantBroadcastModelDao>() {
             @Override
             public TenantBroadcastModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantBroadcastSqlDao.class).getLatestEntry();
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
index 8f0b841..85961c8 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -41,6 +41,8 @@ import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 /**
  * This is a special implementation of the TenantDao that does not rely on caching (CacheControllerDispatcher is not injected and passed
  * to the EntitySqlDaoWrapperInvocationHandler. It only implements the set of operations that does not require caching:
@@ -54,13 +56,13 @@ import com.google.inject.Inject;
 public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, TenantApiException> implements TenantDao {
 
     @Inject
-    public NoCachingTenantDao(final IDBI dbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null, internalCallContextFactory), TenantSqlDao.class);
+    public NoCachingTenantDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, null, null, internalCallContextFactory), TenantSqlDao.class);
     }
 
     @Override
     public TenantModelDao getTenantByApiKey(final String apiKey) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
             @Override
             public TenantModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantSqlDao.class).getByApiKey(apiKey);
@@ -70,7 +72,7 @@ public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Te
 
     @Override
     public List<String> getTenantValueForKey(final String key, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<String>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<String>>() {
             @Override
             public List<String> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<TenantKVModelDao> tenantKV = entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class).getTenantValueForKey(key, context);
@@ -86,7 +88,7 @@ public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Te
 
     @Override
     public TenantKVModelDao getKeyByRecordId(final Long recordId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantKVModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantKVModelDao>() {
             @Override
             public TenantKVModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class).getByRecordId(recordId, context);
@@ -101,7 +103,7 @@ public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Te
 
     @Override
     public TenantModelDao getByRecordId(final Long recordId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TenantModelDao>() {
             @Override
             public TenantModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TenantSqlDao.class).getByRecordId(recordId, context);
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java
index 4d3b4c5..ea5aabd 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.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:
  *
@@ -20,43 +22,48 @@ import java.util.List;
 import java.util.UUID;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.skife.jdbi.v2.IDBI;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultRolledUpUsageDao implements RolledUpUsageDao {
 
     private final RolledUpUsageSqlDao rolledUpUsageSqlDao;
+    private final RolledUpUsageSqlDao roRolledUpUsageSqlDao;
 
     @Inject
-    public DefaultRolledUpUsageDao(final IDBI dbi) {
+    public DefaultRolledUpUsageDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
         this.rolledUpUsageSqlDao = dbi.onDemand(RolledUpUsageSqlDao.class);
+        this.roRolledUpUsageSqlDao = roDbi.onDemand(RolledUpUsageSqlDao.class);
     }
 
     @Override
-    public void record(final Iterable<RolledUpUsageModelDao> usages, final InternalCallContext context){
+    public void record(final Iterable<RolledUpUsageModelDao> usages, final InternalCallContext context) {
         rolledUpUsageSqlDao.create(usages, context);
     }
 
     @Override
-    public Boolean recordsWithTrackingIdExist(final UUID subscriptionId, final String trackingId, final InternalTenantContext context){
-        return rolledUpUsageSqlDao.recordsWithTrackingIdExist(subscriptionId, trackingId, context) != null ;
+    public Boolean recordsWithTrackingIdExist(final UUID subscriptionId, final String trackingId, final InternalTenantContext context) {
+        return rolledUpUsageSqlDao.recordsWithTrackingIdExist(subscriptionId, trackingId, context) != null;
     }
 
     @Override
     public List<RolledUpUsageModelDao> getUsageForSubscription(final UUID subscriptionId, final LocalDate startDate, final LocalDate endDate, final String unitType, final InternalTenantContext context) {
-        return rolledUpUsageSqlDao.getUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), unitType, context);
+        return roRolledUpUsageSqlDao.getUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), unitType, context);
     }
 
     @Override
     public List<RolledUpUsageModelDao> getAllUsageForSubscription(final UUID subscriptionId, final LocalDate startDate, final LocalDate endDate, final InternalTenantContext context) {
-        return rolledUpUsageSqlDao.getAllUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), context);
+        return roRolledUpUsageSqlDao.getAllUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), context);
     }
 
     @Override
     public List<RolledUpUsageModelDao> getRawUsageForAccount(final LocalDate startDate, final LocalDate endDate, final InternalTenantContext context) {
-        return rolledUpUsageSqlDao.getRawUsageForAccount(startDate.toDate(), endDate.toDate(), context);
+        return roRolledUpUsageSqlDao.getRawUsageForAccount(startDate.toDate(), endDate.toDate(), context);
     }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
index 13b75f5..520309d 100644
--- a/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
+++ b/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2012 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
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.UUID;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -52,20 +53,22 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultAuditDao implements AuditDao {
 
-    private final NonEntitySqlDao nonEntitySqlDao;
+    private final NonEntitySqlDao roNonEntitySqlDao;
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
 
     @Inject
-    public DefaultAuditDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        this.nonEntitySqlDao = dbi.onDemand(NonEntitySqlDao.class);
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+    public DefaultAuditDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+        this.roNonEntitySqlDao = roDbi.onDemand(NonEntitySqlDao.class);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
     }
 
     @Override
     public DefaultAccountAuditLogs getAuditLogsForAccountRecordId(final AuditLevel auditLevel, final InternalTenantContext context) {
-        final UUID accountId = nonEntitySqlDao.getIdFromObject(context.getAccountRecordId(), TableName.ACCOUNT.getTableName());
+        final UUID accountId = roNonEntitySqlDao.getIdFromObject(context.getAccountRecordId(), TableName.ACCOUNT.getTableName());
 
         // Lazy evaluate records to minimize the memory footprint (these can yield a lot of results)
         // We usually always want to wrap our queries in an EntitySqlDaoTransactionWrapper... except here.
@@ -115,19 +118,19 @@ public class DefaultAuditDao implements AuditDao {
 
                                                                            if (historyRecordIdIdsCache.get(originalTableNameForHistoryTableName) == null) {
                                                                                if (TableName.ACCOUNT.equals(originalTableNameForHistoryTableName)) {
-                                                                                   final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappingsForAccountsTable(originalTableNameForHistoryTableName.getTableName(),
-                                                                                                                                                                                              input.getTableName().getTableName(),
-                                                                                                                                                                                              tenantContext);
+                                                                                   final Iterable<RecordIdIdMappings> mappings = roNonEntitySqlDao.getHistoryRecordIdIdMappingsForAccountsTable(originalTableNameForHistoryTableName.getTableName(),
+                                                                                                                                                                                                input.getTableName().getTableName(),
+                                                                                                                                                                                                tenantContext);
                                                                                    historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings));
                                                                                } else if (TableName.TAG_DEFINITIONS.equals(originalTableNameForHistoryTableName)) {
-                                                                                   final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappingsForTablesWithoutAccountRecordId(originalTableNameForHistoryTableName.getTableName(),
-                                                                                                                                                                                                             input.getTableName().getTableName(),
-                                                                                                                                                                                                             tenantContext);
+                                                                                   final Iterable<RecordIdIdMappings> mappings = roNonEntitySqlDao.getHistoryRecordIdIdMappingsForTablesWithoutAccountRecordId(originalTableNameForHistoryTableName.getTableName(),
+                                                                                                                                                                                                               input.getTableName().getTableName(),
+                                                                                                                                                                                                               tenantContext);
                                                                                    historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings));
                                                                                } else {
-                                                                                   final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappings(originalTableNameForHistoryTableName.getTableName(),
-                                                                                                                                                                              input.getTableName().getTableName(),
-                                                                                                                                                                              tenantContext);
+                                                                                   final Iterable<RecordIdIdMappings> mappings = roNonEntitySqlDao.getHistoryRecordIdIdMappings(originalTableNameForHistoryTableName.getTableName(),
+                                                                                                                                                                                input.getTableName().getTableName(),
+                                                                                                                                                                                tenantContext);
                                                                                    historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings));
 
                                                                                }
@@ -138,8 +141,8 @@ public class DefaultAuditDao implements AuditDao {
                                                                            objectType = input.getTableName().getObjectType();
 
                                                                            if (recordIdIdsCache.get(input.getTableName()) == null) {
-                                                                               final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getRecordIdIdMappings(input.getTableName().getTableName(),
-                                                                                                                                                                   tenantContext);
+                                                                               final Iterable<RecordIdIdMappings> mappings = roNonEntitySqlDao.getRecordIdIdMappings(input.getTableName().getTableName(),
+                                                                                                                                                                     tenantContext);
                                                                                recordIdIdsCache.put(input.getTableName(), RecordIdIdMappings.toMap(mappings));
                                                                            }
 
@@ -171,7 +174,7 @@ public class DefaultAuditDao implements AuditDao {
     }
 
     private List<AuditLog> doGetAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel, final InternalTenantContext context) {
-        final Long recordId = nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
+        final Long recordId = roNonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
         if (recordId == null) {
             return ImmutableList.<AuditLog>of();
         } else {
@@ -185,8 +188,8 @@ public class DefaultAuditDao implements AuditDao {
             throw new IllegalStateException("History table shouldn't be null for " + tableName);
         }
 
-        final Long targetRecordId = nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
-        final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
+        final Long targetRecordId = roNonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
+        final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
             @Override
             public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<AuditLogModelDao> auditLogsViaHistoryForTargetRecordId = entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsViaHistoryForTargetRecordId(historyTableName.name(),
@@ -200,7 +203,7 @@ public class DefaultAuditDao implements AuditDao {
     }
 
     private List<AuditLog> getAuditLogsForRecordId(final TableName tableName, final UUID auditedEntityId, final Long targetRecordId, final AuditLevel auditLevel, final InternalTenantContext context) {
-        final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
+        final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
             @Override
             public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<AuditLogModelDao> auditLogsForTargetRecordId = entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsForTargetRecordId(tableName.name(),
diff --git a/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java b/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
index 8ceda0e..834aeee 100644
--- a/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
+++ b/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -20,25 +20,24 @@ package org.killbill.billing.util.broadcast.dao;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
-import org.killbill.clock.Clock;
-import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
-import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.TransactionCallback;
 import org.skife.jdbi.v2.TransactionStatus;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
 
 public class DefaultBroadcastDao implements BroadcastDao {
 
     private final IDBI dbi;
-    private final Clock clock;
+    private final IDBI roDbi;
 
     @Inject
-    public DefaultBroadcastDao(final IDBI dbi, final Clock clock) {
+    public DefaultBroadcastDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
         this.dbi = dbi;
-        this.clock = clock;
+        this.roDbi = roDbi;
     }
 
     @Override
@@ -53,10 +52,9 @@ public class DefaultBroadcastDao implements BroadcastDao {
         });
     }
 
-
     @Override
     public List<BroadcastModelDao> getLatestEntriesFrom(final Long recordId) {
-        return dbi.inTransaction(new TransactionCallback<List<BroadcastModelDao>>() {
+        return roDbi.inTransaction(new TransactionCallback<List<BroadcastModelDao>>() {
             @Override
             public List<BroadcastModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
                 final BroadcastSqlDao sqlDao = handle.attach(BroadcastSqlDao.class);
@@ -67,7 +65,7 @@ public class DefaultBroadcastDao implements BroadcastDao {
 
     @Override
     public BroadcastModelDao getLatestEntry() {
-        return dbi.inTransaction(new TransactionCallback<BroadcastModelDao>() {
+        return roDbi.inTransaction(new TransactionCallback<BroadcastModelDao>() {
             @Override
             public BroadcastModelDao inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
                 final BroadcastSqlDao sqlDao = handle.attach(BroadcastSqlDao.class);
diff --git a/util/src/main/java/org/killbill/billing/util/cache/AuditLogCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/AuditLogCacheLoader.java
index fac8514..875920d 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/AuditLogCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/AuditLogCacheLoader.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
@@ -21,6 +21,7 @@ package org.killbill.billing.util.cache;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -29,15 +30,17 @@ import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.dao.AuditSqlDao;
 import org.skife.jdbi.v2.IDBI;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 @Singleton
 public class AuditLogCacheLoader extends BaseCacheLoader<String, List<AuditLogModelDao>> {
 
-    private final AuditSqlDao auditSqlDao;
+    private final AuditSqlDao roAuditSqlDao;
 
     @Inject
-    public AuditLogCacheLoader(final IDBI dbi) {
+    public AuditLogCacheLoader(@Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
         super();
-        this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+        this.roAuditSqlDao = roDbi.onDemand(AuditSqlDao.class);
     }
 
     @Override
@@ -52,6 +55,6 @@ public class AuditLogCacheLoader extends BaseCacheLoader<String, List<AuditLogMo
         final Long targetRecordId = (Long) args[1];
         final InternalTenantContext internalTenantContext = (InternalTenantContext) args[2];
 
-        return auditSqlDao.getAuditLogsForTargetRecordId(tableName, targetRecordId, internalTenantContext);
+        return roAuditSqlDao.getAuditLogsForTargetRecordId(tableName, targetRecordId, internalTenantContext);
     }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/cache/AuditLogViaHistoryCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/AuditLogViaHistoryCacheLoader.java
index 26d215a..55eb6ff 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/AuditLogViaHistoryCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/AuditLogViaHistoryCacheLoader.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
@@ -21,6 +21,7 @@ package org.killbill.billing.util.cache;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -29,15 +30,17 @@ import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.dao.AuditSqlDao;
 import org.skife.jdbi.v2.IDBI;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 @Singleton
 public class AuditLogViaHistoryCacheLoader extends BaseCacheLoader<String, List<AuditLogModelDao>> {
 
-    private final AuditSqlDao auditSqlDao;
+    private final AuditSqlDao roAuditSqlDao;
 
     @Inject
-    public AuditLogViaHistoryCacheLoader(final IDBI dbi) {
+    public AuditLogViaHistoryCacheLoader(@Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
         super();
-        this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+        this.roAuditSqlDao = roDbi.onDemand(AuditSqlDao.class);
     }
 
     @Override
@@ -53,6 +56,6 @@ public class AuditLogViaHistoryCacheLoader extends BaseCacheLoader<String, List<
         final Long targetRecordId = (Long) args[2];
         final InternalTenantContext internalTenantContext = (InternalTenantContext) args[3];
 
-        return auditSqlDao.getAuditLogsViaHistoryForTargetRecordId(tableName, historyTableName, targetRecordId, internalTenantContext);
+        return roAuditSqlDao.getAuditLogsViaHistoryForTargetRecordId(tableName, historyTableName, targetRecordId, internalTenantContext);
     }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
index 9a8abae..41158ff 100644
--- a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
@@ -51,6 +51,7 @@ public class InternalCallContextFactory {
 
     public static final String MDC_KB_ACCOUNT_RECORD_ID = "kb.accountRecordId";
     public static final String MDC_KB_TENANT_RECORD_ID = "kb.tenantRecordId";
+    public static final String MDC_KB_USER_TOKEN = "kb.userToken";
 
     private final ImmutableAccountInternalApi accountInternalApi;
     private final Clock clock;
@@ -159,7 +160,7 @@ public class InternalCallContextFactory {
          * @return internal tenant callcontext
          */
     public InternalTenantContext createInternalTenantContext(final Long tenantRecordId, @Nullable final Long accountRecordId) {
-        populateMDCContext(accountRecordId, tenantRecordId);
+        populateMDCContext(null, accountRecordId, tenantRecordId);
 
         if (accountRecordId == null) {
             return new InternalTenantContext(tenantRecordId);
@@ -245,7 +246,7 @@ public class InternalCallContextFactory {
     public InternalCallContext createInternalCallContextWithoutAccountRecordId(final CallContext context) {
         // If tenant id is null, this will default to the default tenant record id (multi-tenancy disabled)
         final Long tenantRecordId = getTenantRecordIdSafe(context);
-        populateMDCContext(null, tenantRecordId);
+        populateMDCContext(context.getUserToken(), null, tenantRecordId);
         return new InternalCallContext(tenantRecordId, context, clock.getUTCNow());
     }
 
@@ -254,7 +255,7 @@ public class InternalCallContextFactory {
         final ImmutableAccountData immutableAccountData = getImmutableAccountData(accountRecordId, context.getTenantRecordId());
         final DateTimeZone fixedOffsetTimeZone = immutableAccountData.getFixedOffsetTimeZone();
         final DateTime referenceTime = immutableAccountData.getReferenceTime();
-        populateMDCContext(accountRecordId, context.getTenantRecordId());
+        populateMDCContext(context.getUserToken(), accountRecordId, context.getTenantRecordId());
         return new InternalCallContext(context, accountRecordId, fixedOffsetTimeZone, referenceTime, clock.getUTCNow());
     }
 
@@ -263,12 +264,12 @@ public class InternalCallContextFactory {
         // See DefaultImmutableAccountData implementation
         final DateTimeZone fixedOffsetTimeZone = AccountDateTimeUtils.getFixedOffsetTimeZone(accountModelDao);
         final DateTime referenceTime = accountModelDao.getReferenceTime();
-        populateMDCContext(accountRecordId, context.getTenantRecordId());
+        populateMDCContext(context.getUserToken(), accountRecordId, context.getTenantRecordId());
         return new InternalCallContext(context, accountRecordId, fixedOffsetTimeZone, referenceTime, clock.getUTCNow());
     }
 
     public InternalCallContext createInternalCallContext(final DateTimeZone fixedOffsetTimeZone, final DateTime referenceTime, final Long accountRecordId, final InternalCallContext context) {
-        populateMDCContext(accountRecordId, context.getTenantRecordId());
+        populateMDCContext(context.getUserToken(), accountRecordId, context.getTenantRecordId());
         return new InternalCallContext(context, accountRecordId, fixedOffsetTimeZone, referenceTime, clock.getUTCNow());
     }
 
@@ -299,7 +300,7 @@ public class InternalCallContextFactory {
             referenceTime = immutableAccountData.getReferenceTime();
         }
 
-        populateMDCContext(accountRecordId, nonNulTenantRecordId);
+        populateMDCContext(userToken, accountRecordId, nonNulTenantRecordId);
 
         return new InternalCallContext(nonNulTenantRecordId,
                                        accountRecordId,
@@ -327,11 +328,12 @@ public class InternalCallContextFactory {
         }
     }
 
-    private void populateMDCContext(@Nullable final Long accountRecordId, final Long tenantRecordId) {
+    private void populateMDCContext(@Nullable final UUID userToken, @Nullable final Long accountRecordId, final Long tenantRecordId) {
         if (accountRecordId != null) {
             MDC.put(MDC_KB_ACCOUNT_RECORD_ID, String.valueOf(accountRecordId));
         }
         MDC.put(MDC_KB_TENANT_RECORD_ID, String.valueOf(tenantRecordId));
+        MDC.put(MDC_KB_USER_TOKEN, userToken != null ? userToken.toString() : null);
     }
 
     //
diff --git a/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java b/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java
index d89595a..3cb5167 100644
--- a/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java
+++ b/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.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
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
+import javax.inject.Named;
 
 import org.killbill.billing.BillingExceptionBase;
 import org.killbill.billing.ErrorCode;
@@ -58,6 +59,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, CustomField, CustomFieldApiException> implements CustomFieldDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultCustomFieldDao.class);
@@ -65,15 +68,15 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
     private final PersistentBus bus;
 
     @Inject
-    public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher,
+    public DefaultCustomFieldDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher,
                                  final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final PersistentBus bus) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), CustomFieldSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), CustomFieldSqlDao.class);
         this.bus = bus;
     }
 
     @Override
     public List<CustomFieldModelDao> getCustomFieldsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
             @Override
             public List<CustomFieldModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(CustomFieldSqlDao.class).getCustomFieldsForObject(objectId, objectType, context);
@@ -95,7 +98,7 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
 
     @Override
     public List<CustomFieldModelDao> getCustomFieldsForAccount(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
             @Override
             public List<CustomFieldModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(CustomFieldSqlDao.class).getByAccountRecordId(context);
@@ -105,7 +108,7 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
 
     @Override
     public void deleteCustomFields(final Iterable<UUID> customFieldIds, final InternalCallContext context) throws CustomFieldApiException {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final CustomFieldSqlDao sqlDao = entitySqlDaoWrapperFactory.become(CustomFieldSqlDao.class);
@@ -126,9 +129,9 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
     @Override
     public void updateCustomFields(final Iterable<CustomFieldModelDao> customFieldIds, final InternalCallContext context) throws CustomFieldApiException {
 
-        transactionalSqlDao.execute(CustomFieldApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, CustomFieldApiException.class, new EntitySqlDaoTransactionWrapper<Void>() {
 
-            private void validateCustomField(final CustomFieldModelDao input,  @Nullable CustomFieldModelDao existing) throws CustomFieldApiException {
+            private void validateCustomField(final CustomFieldModelDao input, @Nullable CustomFieldModelDao existing) throws CustomFieldApiException {
                 if (existing == null) {
                     throw new CustomFieldApiException(ErrorCode.CUSTOM_FIELD_DOES_NOT_EXISTS_FOR_ID, input.getId());
                 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/DefaultNonEntityDao.java b/util/src/main/java/org/killbill/billing/util/dao/DefaultNonEntityDao.java
index 7cec9b9..5e8c63d 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/DefaultNonEntityDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/DefaultNonEntityDao.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
@@ -22,6 +22,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.cache.CacheController;
@@ -37,15 +38,17 @@ import org.skife.jdbi.v2.sqlobject.SqlObjectBuilder;
 
 import com.google.common.base.Preconditions;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultNonEntityDao implements NonEntityDao {
 
-    private final NonEntitySqlDao nonEntitySqlDao;
+    private final NonEntitySqlDao roNonEntitySqlDao;
     private final WithCaching<String, Long> withCachingObjectId;
     private final WithCaching<String, UUID> withCachingRecordId;
 
     @Inject
-    public DefaultNonEntityDao(final IDBI dbi) {
-        this.nonEntitySqlDao = dbi.onDemand(NonEntitySqlDao.class);
+    public DefaultNonEntityDao(@Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
+        this.roNonEntitySqlDao = roDbi.onDemand(NonEntitySqlDao.class);
         this.withCachingObjectId = new WithCaching<String, Long>();
         this.withCachingRecordId = new WithCaching<String, UUID>();
     }
@@ -66,7 +69,7 @@ public class DefaultNonEntityDao implements NonEntityDao {
         return withCachingObjectId.withCaching(new OperationRetrieval<Long>() {
             @Override
             public Long doRetrieve(final ObjectType objectType) {
-                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? nonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
+                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? roNonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
                 return inTransactionNonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
             }
         }, objectId.toString(), objectType, tableName, cache);
@@ -86,7 +89,7 @@ public class DefaultNonEntityDao implements NonEntityDao {
         return withCachingObjectId.withCaching(new OperationRetrieval<Long>() {
             @Override
             public Long doRetrieve(final ObjectType objectType) {
-                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? nonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
+                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? roNonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
 
                 switch (tableName) {
                     case TENANT:
@@ -118,7 +121,7 @@ public class DefaultNonEntityDao implements NonEntityDao {
         return withCachingObjectId.withCaching(new OperationRetrieval<Long>() {
             @Override
             public Long doRetrieve(final ObjectType objectType) {
-                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? nonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
+                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? roNonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
 
                 switch (tableName) {
                     case TENANT:
@@ -150,7 +153,7 @@ public class DefaultNonEntityDao implements NonEntityDao {
         return withCachingRecordId.withCaching(new OperationRetrieval<UUID>() {
             @Override
             public UUID doRetrieve(final ObjectType objectType) {
-                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? nonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
+                final NonEntitySqlDao inTransactionNonEntitySqlDao = handle == null ? roNonEntitySqlDao : SqlObjectBuilder.attach(handle, NonEntitySqlDao.class);
                 return inTransactionNonEntitySqlDao.getIdFromObject(recordId, tableName.getTableName());
             }
         }, String.valueOf(recordId), objectType, tableName, cache);
@@ -164,7 +167,7 @@ public class DefaultNonEntityDao implements NonEntityDao {
 
     @Override
     public Long retrieveHistoryTargetRecordId(@Nullable final Long recordId, final TableName tableName) {
-        return nonEntitySqlDao.getHistoryTargetRecordId(recordId, tableName.getTableName());
+        return roNonEntitySqlDao.getHistoryTargetRecordId(recordId, tableName.getTableName());
     }
 
     private interface OperationRetrieval<TypeOut> {
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/DefaultPaginationSqlDaoHelper.java b/util/src/main/java/org/killbill/billing/util/entity/dao/DefaultPaginationSqlDaoHelper.java
index d359a19..531b4bf 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/DefaultPaginationSqlDaoHelper.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/DefaultPaginationSqlDaoHelper.java
@@ -61,7 +61,7 @@ public class DefaultPaginationSqlDaoHelper {
         // We still need to know the actual number of results, mainly for the UI so that it knows if it needs to fetch
         // more pages.
         // Note: for simple pagination (no search filter), this will be computed below instead (MaxNbRecords == TotalNbRecords)
-        final Long totalNbRecordsOrNull = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+        final Long totalNbRecordsOrNull = transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Long>() {
             @Override
             public Long inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final EntitySqlDao<M, E> sqlDao = entitySqlDaoWrapperFactory.become(sqlDaoClazz);
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
index 8f02941..17040e4 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
@@ -63,14 +63,14 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public void create(final M entity, final InternalCallContext context) throws U {
-        final M refreshedEntity = transactionalSqlDao.execute(targetExceptionClass, getCreateEntitySqlDaoTransactionWrapper(entity, context));
+        final M refreshedEntity = transactionalSqlDao.execute(false, targetExceptionClass, getCreateEntitySqlDaoTransactionWrapper(entity, context));
         // Populate the caches only after the transaction has been committed, in case of rollbacks
         transactionalSqlDao.populateCaches(refreshedEntity);
     }
 
 
     public void create(final Iterable<M> entities, final InternalCallContext context) throws U {
-        final List<M> refreshedEntities = transactionalSqlDao.execute(targetExceptionClass, getCreateEntitySqlDaoTransactionWrapper(entities, context));
+        final List<M> refreshedEntities = transactionalSqlDao.execute(false, targetExceptionClass, getCreateEntitySqlDaoTransactionWrapper(entities, context));
         // Populate the caches only after the transaction has been committed, in case of rollbacks
         for (M refreshedEntity : refreshedEntities) {
             transactionalSqlDao.populateCaches(refreshedEntity);
@@ -134,7 +134,7 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public Long getRecordId(final UUID id, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Long>() {
 
             @Override
             public Long inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -146,7 +146,7 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public M getByRecordId(final Long recordId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<M>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<M>() {
 
             @Override
             public M inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -158,7 +158,7 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public M getById(final UUID id, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<M>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<M>() {
 
             @Override
             public M inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -205,7 +205,7 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public Long getCount(final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Long>() {
 
             @Override
             public Long inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -217,7 +217,7 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
 
     @Override
     public void test(final InternalTenantContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
index 4cfd83a..60934fb 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
@@ -40,14 +40,16 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
     private final Logger logger = LoggerFactory.getLogger(EntitySqlDaoTransactionalJdbiWrapper.class);
 
     private final IDBI dbi;
+    private final IDBI roDbi;
     private final Clock clock;
     private final CacheControllerDispatcher cacheControllerDispatcher;
     private final NonEntityDao nonEntityDao;
     private final InternalCallContextFactory internalCallContextFactory;
 
-    public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+    public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi, final IDBI roDbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
                                                 final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
         this.dbi = dbi;
+        this.roDbi = roDbi;
         this.clock = clock;
         this.cacheControllerDispatcher = cacheControllerDispatcher;
         this.nonEntityDao = nonEntityDao;
@@ -79,27 +81,29 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
     interface InitialEntitySqlDao extends EntitySqlDao<EntityModelDao<Entity>, Entity> {}
 
     /**
-     * @param entitySqlDaoTransactionWrapper transaction to execute
      * @param <ReturnType>                   object type to return from the transaction
+     * @param ro                             whether to use the read-only connection
+     * @param entitySqlDaoTransactionWrapper transaction to execute
      * @return result from the transaction fo type ReturnType
      */
-    public <ReturnType> ReturnType execute(final EntitySqlDaoTransactionWrapper<ReturnType> entitySqlDaoTransactionWrapper) {
+    public <ReturnType> ReturnType execute(final boolean ro, final EntitySqlDaoTransactionWrapper<ReturnType> entitySqlDaoTransactionWrapper) {
         final String debugInfo = logger.isDebugEnabled() ? getDebugInfo() : null;
+        final String debugPrefix = ro ? "RO" : "RW";
 
-        final Handle handle = dbi.open();
-        logger.debug("DBI handle created, transaction: {}", debugInfo);
+        final Handle handle = ro ? roDbi.open() : dbi.open();
+        logger.debug("[{}] DBI handle created, transaction: {}", debugPrefix, debugInfo);
         try {
             final EntitySqlDao<EntityModelDao<Entity>, Entity> entitySqlDao = handle.attach(InitialEntitySqlDao.class);
             // The transaction isolation level is now set at the pool level: this avoids 3 roundtrips for each transaction
             // Note that if the pool isn't used (tests or PostgreSQL), the transaction level will depend on the DB configuration
             //return entitySqlDao.inTransaction(TransactionIsolationLevel.READ_COMMITTED, new JdbiTransaction<ReturnType, EntityModelDao<Entity>, Entity>(handle, entitySqlDaoTransactionWrapper));
-            logger.debug("Starting transaction {}", debugInfo);
+            logger.debug("[{}] Starting transaction {}", debugPrefix, debugInfo);
             final ReturnType returnType = entitySqlDao.inTransaction(new JdbiTransaction<ReturnType, EntityModelDao<Entity>, Entity>(handle, entitySqlDaoTransactionWrapper));
-            logger.debug("Exiting  transaction {}, returning {}", debugInfo, returnType);
+            logger.debug("[{}] Exiting  transaction {}, returning {}", debugPrefix, debugInfo, returnType);
             return returnType;
         } finally {
             handle.close();
-            logger.debug("DBI handle closed,  transaction: {}", debugInfo);
+            logger.debug("[{}] DBI handle closed,  transaction: {}", debugPrefix, debugInfo);
         }
     }
 
@@ -108,18 +112,19 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
     // to send bus events, record notifications where we need to keep the Connection through the jDBI Handle.
     //
     public <M extends EntityModelDao<E>, E extends Entity, T extends EntitySqlDao<M, E>> T onDemandForStreamingResults(final Class<T> sqlObjectType) {
-        return dbi.onDemand(sqlObjectType);
+        return roDbi.onDemand(sqlObjectType);
     }
 
     /**
-     * @param entitySqlDaoTransactionWrapper transaction to execute
      * @param <ReturnType>                   object type to return from the transaction
      * @param <E>                            checked exception which can be thrown from the transaction
+     * @param ro                             whether to use the read-only connection
+     * @param entitySqlDaoTransactionWrapper transaction to execute
      * @return result from the transaction fo type ReturnType
      */
-    public <ReturnType, E extends Exception> ReturnType execute(@Nullable final Class<E> exception, final EntitySqlDaoTransactionWrapper<ReturnType> entitySqlDaoTransactionWrapper) throws E {
+    public <ReturnType, E extends Exception> ReturnType execute(final boolean ro, @Nullable final Class<E> exception, final EntitySqlDaoTransactionWrapper<ReturnType> entitySqlDaoTransactionWrapper) throws E {
         try {
-            return execute(entitySqlDaoTransactionWrapper);
+            return execute(ro, entitySqlDaoTransactionWrapper);
         } catch (final RuntimeException e) {
             if (e.getCause() != null && exception != null && e.getCause().getClass().isAssignableFrom(exception)) {
                 throw (E) e.getCause();
diff --git a/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java b/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java
index 0e78d66..782de0f 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java
@@ -1,6 +1,6 @@
 /*
- * 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,8 +44,13 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
 
+import static org.killbill.billing.platform.glue.KillBillPlatformModuleBase.MAIN_RO_DATA_SOURCE_ID;
+
 public class IDBISetup {
 
+    // See binding in KillbillPlatformModule
+    public static final String MAIN_RO_IDBI_NAMED = MAIN_RO_DATA_SOURCE_ID;
+
     public static List<? extends ResultSetMapperFactory> mapperFactoriesToRegister() {
         final Builder<ResultSetMapperFactory> builder = ImmutableList.<ResultSetMapperFactory>builder();
         builder.add(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
diff --git a/util/src/main/java/org/killbill/billing/util/glue/JDBCSessionDaoProvider.java b/util/src/main/java/org/killbill/billing/util/glue/JDBCSessionDaoProvider.java
index 106bc83..ac59621 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/JDBCSessionDaoProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/JDBCSessionDaoProvider.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,31 +19,35 @@
 package org.killbill.billing.util.glue;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Provider;
 
 import org.apache.shiro.session.mgt.DefaultSessionManager;
 import org.apache.shiro.session.mgt.SessionManager;
-import org.skife.jdbi.v2.IDBI;
-
 import org.killbill.billing.util.config.definition.RbacConfig;
 import org.killbill.billing.util.security.shiro.dao.JDBCSessionDao;
+import org.skife.jdbi.v2.IDBI;
+
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
 
 public class JDBCSessionDaoProvider implements Provider<JDBCSessionDao> {
 
     private final SessionManager sessionManager;
     private final IDBI dbi;
+    private final IDBI roDbi;
     private final RbacConfig rbacConfig;
 
     @Inject
-    public JDBCSessionDaoProvider(final IDBI dbi, final SessionManager sessionManager, final RbacConfig rbacConfig) {
+    public JDBCSessionDaoProvider(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final SessionManager sessionManager, final RbacConfig rbacConfig) {
         this.sessionManager = sessionManager;
         this.dbi = dbi;
+        this.roDbi = roDbi;
         this.rbacConfig = rbacConfig;
     }
 
     @Override
     public JDBCSessionDao get() {
-        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi);
+        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi, roDbi);
 
         if (sessionManager instanceof DefaultSessionManager) {
             final DefaultSessionManager defaultSessionManager = (DefaultSessionManager) sessionManager;
diff --git a/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java b/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
index 2c951ba..892c1db 100644
--- a/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
+++ b/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -20,9 +20,9 @@ package org.killbill.billing.util.nodes.dao;
 import java.util.Date;
 import java.util.List;
 
+import javax.inject.Named;
+
 import org.killbill.clock.Clock;
-import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
-import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.TransactionCallback;
@@ -30,20 +30,23 @@ import org.skife.jdbi.v2.TransactionStatus;
 
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultNodeInfoDao implements NodeInfoDao {
 
     private final IDBI dbi;
+    private final IDBI roDbi;
     private final Clock clock;
 
     @Inject
-    public DefaultNodeInfoDao(final IDBI dbi, final Clock clock) {
+    public DefaultNodeInfoDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final Clock clock) {
         this.dbi = dbi;
+        this.roDbi = roDbi;
         this.clock = clock;
     }
 
     @Override
     public void create(final NodeInfoModelDao nodeInfoModelDao) {
-
         dbi.inTransaction(new TransactionCallback<Void>() {
             @Override
             public Void inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
@@ -70,7 +73,6 @@ public class DefaultNodeInfoDao implements NodeInfoDao {
         });
     }
 
-
     @Override
     public void delete(final String nodeName) {
         dbi.inTransaction(new TransactionCallback<Void>() {
@@ -85,7 +87,7 @@ public class DefaultNodeInfoDao implements NodeInfoDao {
 
     @Override
     public List<NodeInfoModelDao> getAll() {
-        return dbi.inTransaction(new TransactionCallback<List<NodeInfoModelDao>>() {
+        return roDbi.inTransaction(new TransactionCallback<List<NodeInfoModelDao>>() {
             @Override
             public List<NodeInfoModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
                 final NodeInfoSqlDao sqlDao = handle.attach(NodeInfoSqlDao.class);
@@ -96,7 +98,7 @@ public class DefaultNodeInfoDao implements NodeInfoDao {
 
     @Override
     public NodeInfoModelDao getByNodeName(final String nodeName) {
-        return dbi.inTransaction(new TransactionCallback<NodeInfoModelDao>() {
+        return roDbi.inTransaction(new TransactionCallback<NodeInfoModelDao>() {
             @Override
             public NodeInfoModelDao inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
                 final NodeInfoSqlDao sqlDao = handle.attach(NodeInfoSqlDao.class);
@@ -104,5 +106,4 @@ public class DefaultNodeInfoDao implements NodeInfoDao {
             }
         });
     }
-
 }
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionDao.java
index e241a20..bf5c760 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionDao.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
@@ -24,6 +24,7 @@ import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.apache.shiro.session.Session;
 import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
@@ -35,17 +36,21 @@ import org.slf4j.LoggerFactory;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class JDBCSessionDao extends CachingSessionDAO {
 
     private static final Logger log = LoggerFactory.getLogger(JDBCSessionDao.class);
 
     private final JDBCSessionSqlDao jdbcSessionSqlDao;
+    private final JDBCSessionSqlDao roJdbcSessionSqlDao;
 
     private final Cache<Serializable, Boolean> noUpdateSessionsCache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.SECONDS).build();
 
     @Inject
-    public JDBCSessionDao(final IDBI dbi) {
+    public JDBCSessionDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
         this.jdbcSessionSqlDao = dbi.onDemand(JDBCSessionSqlDao.class);
+        this.roJdbcSessionSqlDao = roDbi.onDemand(JDBCSessionSqlDao.class);
     }
 
     @Override
@@ -80,7 +85,7 @@ public class JDBCSessionDao extends CachingSessionDAO {
         }
 
         final String sessionIdString = sessionId.toString();
-        final SessionModelDao sessionModelDao = jdbcSessionSqlDao.read(sessionIdString);
+        final SessionModelDao sessionModelDao = roJdbcSessionSqlDao.read(sessionIdString);
 
         if (sessionModelDao == null) {
             return null;
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/realm/KillBillJdbcRealm.java b/util/src/main/java/org/killbill/billing/util/security/shiro/realm/KillBillJdbcRealm.java
index 6970497..4cb7d7b 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/realm/KillBillJdbcRealm.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/realm/KillBillJdbcRealm.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -37,7 +37,7 @@ public class KillBillJdbcRealm extends JdbcRealm {
     private final SecurityConfig securityConfig;
 
     @Inject
-    public KillBillJdbcRealm(@Named(KillBillPlatformModuleBase.SHIRO_DATA_SOURCE_ID_NAMED) final DataSource dataSource, final SecurityConfig securityConfig) {
+    public KillBillJdbcRealm(@Named(KillBillPlatformModuleBase.SHIRO_DATA_SOURCE_ID) final DataSource dataSource, final SecurityConfig securityConfig) {
         super();
         this.dataSource = dataSource;
         this.securityConfig = securityConfig;
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java
index b6342ee..a2398a1 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.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
@@ -22,25 +22,21 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
 
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper.Ordering;
-import org.skife.jdbi.v2.IDBI;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import javax.inject.Named;
 
 import org.killbill.billing.BillingExceptionBase;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
-import org.killbill.bus.api.PersistentBus;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.clock.Clock;
 import org.killbill.billing.events.TagInternalEvent;
 import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.entity.Pagination;
+import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper.Ordering;
 import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper.PaginationIteratorBuilder;
 import org.killbill.billing.util.entity.dao.EntityDaoBase;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
@@ -50,6 +46,11 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.killbill.billing.util.tag.Tag;
 import org.killbill.billing.util.tag.api.user.TagEventBuilder;
+import org.killbill.bus.api.PersistentBus;
+import org.killbill.clock.Clock;
+import org.skife.jdbi.v2.IDBI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
@@ -57,6 +58,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiException> implements TagDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultTagDao.class);
@@ -65,16 +68,16 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
     private final PersistentBus bus;
 
     @Inject
-    public DefaultTagDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
+    public DefaultTagDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
                          final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagSqlDao.class);
         this.tagEventBuilder = tagEventBuilder;
         this.bus = bus;
     }
 
     @Override
     public List<TagModelDao> getTagsForObject(final UUID objectId, final ObjectType objectType, final boolean includedDeleted, final InternalTenantContext internalTenantContext) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
             @Override
             public List<TagModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TagSqlDao tagSqlDao = entitySqlDaoWrapperFactory.become(TagSqlDao.class);
@@ -100,7 +103,7 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
 
     @Override
     public List<TagModelDao> getTagsForAccount(final boolean includedDeleted, final InternalTenantContext internalTenantContext) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
             @Override
             public List<TagModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TagSqlDao tagSqlDao = entitySqlDaoWrapperFactory.become(TagSqlDao.class);
@@ -181,13 +184,13 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
 
     @Override
     public void create(final TagModelDao entity, final InternalCallContext context) throws TagApiException {
-        transactionalSqlDao.execute(TagApiException.class, getCreateEntitySqlDaoTransactionWrapper(entity, context));
+        transactionalSqlDao.execute(false, TagApiException.class, getCreateEntitySqlDaoTransactionWrapper(entity, context));
     }
 
     @Override
     public void deleteTag(final UUID objectId, final ObjectType objectType, final UUID tagDefinitionId, final InternalCallContext context) throws TagApiException {
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
index dfa1331..c31ad6c 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2011 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
@@ -22,9 +22,10 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.killbill.billing.BillingExceptionBase;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -53,6 +54,8 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.Iterators;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao, TagDefinition, TagDefinitionApiException> implements TagDefinitionDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultTagDefinitionDao.class);
@@ -60,18 +63,17 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
     private final TagEventBuilder tagEventBuilder;
     private final PersistentBus bus;
 
-
     @Inject
-    public DefaultTagDefinitionDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
+    public DefaultTagDefinitionDao(final IDBI dbi, @Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
                                    final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagDefinitionSqlDao.class);
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagDefinitionSqlDao.class);
         this.tagEventBuilder = tagEventBuilder;
         this.bus = bus;
     }
 
     @Override
     public List<TagDefinitionModelDao> getTagDefinitions(final boolean includeSystemTags, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagDefinitionModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TagDefinitionModelDao>>() {
             @Override
             public List<TagDefinitionModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 // Get user definitions from the database
@@ -89,7 +91,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
 
     @Override
     public TagDefinitionModelDao getByName(final String definitionName, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
             @Override
             public TagDefinitionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TagDefinitionModelDao tagDefinitionModelDao = SystemTags.lookup(definitionName);
@@ -100,7 +102,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
 
     @Override
     public TagDefinitionModelDao getById(final UUID definitionId, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
             @Override
             public TagDefinitionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final TagDefinitionModelDao tagDefinitionModelDao = SystemTags.lookup(definitionId);
@@ -111,7 +113,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
 
     @Override
     public List<TagDefinitionModelDao> getByIds(final Collection<UUID> definitionIds, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagDefinitionModelDao>>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<List<TagDefinitionModelDao>>() {
             @Override
             public List<TagDefinitionModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final List<TagDefinitionModelDao> result = new LinkedList<TagDefinitionModelDao>();
@@ -144,7 +146,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
         }
 
         try {
-            return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
+            return transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<TagDefinitionModelDao>() {
                 @Override
                 public TagDefinitionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                     final TagDefinitionSqlDao tagDefinitionSqlDao = entitySqlDaoWrapperFactory.become(TagDefinitionSqlDao.class);
@@ -190,7 +192,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
     @Override
     public void deleteById(final UUID definitionId, final InternalCallContext context) throws TagDefinitionApiException {
         try {
-            transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
                 @Override
                 public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                     final TagDefinitionSqlDao tagDefinitionSqlDao = entitySqlDaoWrapperFactory.become(TagDefinitionSqlDao.class);
diff --git a/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaDao.java b/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaDao.java
index 002d35b..2922ce2 100644
--- a/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaDao.java
+++ b/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaDao.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2014 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:
  *
@@ -19,22 +21,24 @@ package org.killbill.billing.util.validation.dao;
 import java.util.List;
 
 import javax.annotation.Nullable;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.skife.jdbi.v2.IDBI;
-
 import org.killbill.billing.util.validation.DefaultColumnInfo;
+import org.skife.jdbi.v2.IDBI;
 
 import com.google.inject.Inject;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 @Singleton
 public class DatabaseSchemaDao {
 
-    private final DatabaseSchemaSqlDao dao;
+    private final DatabaseSchemaSqlDao roDatabaseSchemaSqlDao;
 
     @Inject
-    public DatabaseSchemaDao(final IDBI dbi) {
-        this.dao = dbi.onDemand(DatabaseSchemaSqlDao.class);
+    public DatabaseSchemaDao(@Named(MAIN_RO_IDBI_NAMED) final IDBI roDbi) {
+        this.roDatabaseSchemaSqlDao = roDbi.onDemand(DatabaseSchemaSqlDao.class);
     }
 
     public List<DefaultColumnInfo> getColumnInfoList() {
@@ -42,6 +46,6 @@ public class DatabaseSchemaDao {
     }
 
     public List<DefaultColumnInfo> getColumnInfoList(@Nullable final String schemaName) {
-        return dao.getSchemaInfo(schemaName);
+        return roDatabaseSchemaSqlDao.getSchemaInfo(schemaName);
     }
 }
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestNoDBModule.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestNoDBModule.java
index 9decb42..ba6716a 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestNoDBModule.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestNoDBModule.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
@@ -20,6 +20,12 @@ package org.killbill.billing;
 
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.platform.test.glue.TestPlatformModuleNoDB;
+import org.killbill.billing.util.glue.IDBISetup;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 
 public class GuicyKillbillTestNoDBModule extends GuicyKillbillTestModule {
 
@@ -33,4 +39,11 @@ public class GuicyKillbillTestNoDBModule extends GuicyKillbillTestModule {
 
         install(new TestPlatformModuleNoDB(configSource));
     }
+
+    @Provides
+    @Singleton
+    @Named(IDBISetup.MAIN_RO_IDBI_NAMED)
+    protected IDBI provideRoIDBI(final IDBI idbi) {
+        return idbi;
+    }
 }
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
index 757b8d4..719cff7 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.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,6 +19,7 @@
 package org.killbill.billing;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.sql.DataSource;
 
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
@@ -29,6 +32,8 @@ import org.testng.annotations.AfterSuite;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.BeforeSuite;
 
+import static org.killbill.billing.util.glue.IDBISetup.MAIN_RO_IDBI_NAMED;
+
 public class GuicyKillbillTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite {
 
     private static final Logger log = LoggerFactory.getLogger(GuicyKillbillTestSuiteWithEmbeddedDB.class);
@@ -43,8 +48,11 @@ public class GuicyKillbillTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
     protected IDBI dbi;
 
     @Inject
-    protected CacheControllerDispatcher controlCacheDispatcher;
+    @Named(MAIN_RO_IDBI_NAMED)
+    protected IDBI roDbi;
 
+    @Inject
+    protected CacheControllerDispatcher controlCacheDispatcher;
 
     @BeforeSuite(groups = "slow")
     public void beforeSuite() throws Exception {
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestWithEmbeddedDBModule.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestWithEmbeddedDBModule.java
index edeef1b..330d1a2 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestWithEmbeddedDBModule.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestWithEmbeddedDBModule.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
@@ -22,6 +22,12 @@ import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.platform.test.PlatformDBTestingHelper;
 import org.killbill.billing.platform.test.config.TestKillbillConfigSource;
 import org.killbill.billing.platform.test.glue.TestPlatformModuleWithEmbeddedDB;
+import org.killbill.billing.util.glue.IDBISetup;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 
 public class GuicyKillbillTestWithEmbeddedDBModule extends GuicyKillbillTestModule {
 
@@ -49,6 +55,13 @@ public class GuicyKillbillTestWithEmbeddedDBModule extends GuicyKillbillTestModu
             super(configSource, withOSGI, (TestKillbillConfigSource) configSource);
         }
 
+        @Provides
+        @Singleton
+        @Named(IDBISetup.MAIN_RO_IDBI_NAMED)
+        protected IDBI provideRoIDBIInAComplicatedWayBecauseOf627(final IDBI idbi) {
+            return idbi;
+        }
+
         @Override
         protected PlatformDBTestingHelper getPlatformDBTestingHelper() {
             return DBTestingHelper.get();
diff --git a/util/src/test/java/org/killbill/billing/util/cache/TestCache.java b/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
index d24810c..e3d9da0 100644
--- a/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
+++ b/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
@@ -35,7 +35,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
     private EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
 
     private Long getTagRecordId(final UUID tagId) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<Long>() {
             @Override
             public Long inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TagSqlDao.class).getRecordId(tagId.toString(), internalCallContext);
@@ -60,7 +60,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void testCacheRecordId() throws Exception {
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
         final TagModelDao tag = new TagModelDao(clock.getUTCNow(), UUID.randomUUID(), UUID.randomUUID(), ObjectType.TAG);
 
         // Verify we start with nothing in the cache
@@ -88,7 +88,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void testAllCachesAfterGetById() throws Exception {
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
         final TagModelDao tag = new TagModelDao(clock.getUTCNow(), UUID.randomUUID(), UUID.randomUUID(), ObjectType.TAG);
 
         insertTag(tag);
@@ -121,7 +121,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
     }
 
     private void insertTag(final TagModelDao modelDao) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        transactionalSqlDao.execute(false, new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 entitySqlDaoWrapperFactory.become(TagSqlDao.class).create(modelDao, internalCallContext);
@@ -131,7 +131,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
     }
 
     private TagModelDao getById(final UUID id) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<TagModelDao>() {
+        return transactionalSqlDao.execute(true, new EntitySqlDaoTransactionWrapper<TagModelDao>() {
             @Override
             public TagModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(TagSqlDao.class).getById(id.toString(), internalCallContext);
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestEntityBaseDaoException.java b/util/src/test/java/org/killbill/billing/util/dao/TestEntityBaseDaoException.java
index 82d8eaa..1504340 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestEntityBaseDaoException.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestEntityBaseDaoException.java
@@ -1,6 +1,6 @@
 /*
- * 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
@@ -51,7 +51,7 @@ public class TestEntityBaseDaoException extends UtilTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void testWithCreateException() throws Exception {
-        final EntitySqlDaoTransactionalJdbiWrapper entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, nonEntityDao, null);
+        final EntitySqlDaoTransactionalJdbiWrapper entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, null, nonEntityDao, null);
         final TestEntityBaseDao test = new TestEntityBaseDao(entitySqlDaoTransactionalJdbiWrapper, KombuchaSqlDao.class);
 
         final KombuchaModelDao entity = new KombuchaModelDao() {
diff --git a/util/src/test/java/org/killbill/billing/util/security/shiro/dao/TestJDBCSessionDao.java b/util/src/test/java/org/killbill/billing/util/security/shiro/dao/TestJDBCSessionDao.java
index c8da341..eaada79 100644
--- a/util/src/test/java/org/killbill/billing/util/security/shiro/dao/TestJDBCSessionDao.java
+++ b/util/src/test/java/org/killbill/billing/util/security/shiro/dao/TestJDBCSessionDao.java
@@ -30,7 +30,7 @@ public class TestJDBCSessionDao extends UtilTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void testH2AndInvalidSessionId() {
-        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi);
+        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi, roDbi);
 
         // We need to create some data to force H2 to build the query
         // (otherwise, the read path is optimized and the bug is not triggered)
@@ -44,7 +44,7 @@ public class TestJDBCSessionDao extends UtilTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testCRUD() throws Exception {
         // Note! We are testing the do* methods here to bypass the caching layer
-        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi);
+        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi, roDbi);
 
         // Retrieve
         final SimpleSession session = createSession();
diff --git a/util/src/test/java/org/killbill/billing/util/security/TestPermissionAnnotationMethodInterceptor.java b/util/src/test/java/org/killbill/billing/util/security/TestPermissionAnnotationMethodInterceptor.java
index c4a8c52..8a5cd77 100644
--- a/util/src/test/java/org/killbill/billing/util/security/TestPermissionAnnotationMethodInterceptor.java
+++ b/util/src/test/java/org/killbill/billing/util/security/TestPermissionAnnotationMethodInterceptor.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
@@ -40,6 +40,9 @@ import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
+import com.google.inject.name.Names;
+
+import static org.killbill.billing.platform.glue.KillBillPlatformModuleBase.MAIN_RO_DATA_SOURCE_ID;
 
 public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB {
 
@@ -84,6 +87,7 @@ public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB
                                                            @Override
                                                            protected void configure() {
                                                                bind(IDBI.class).toInstance(Mockito.mock(IDBI.class));
+                                                               bind(IDBI.class).annotatedWith(Names.named(MAIN_RO_DATA_SOURCE_ID)).toInstance(Mockito.mock(IDBI.class));
                                                                bind(TenantInternalApi.class).toInstance(Mockito.mock(TenantInternalApi.class));
                                                                bind(NonEntityDao.class).toInstance(Mockito.mock(NonEntityDao.class));
                                                            }
@@ -114,6 +118,7 @@ public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB
                                                            @Override
                                                            public void configure() {
                                                                bind(IDBI.class).toInstance(Mockito.mock(IDBI.class));
+                                                               bind(IDBI.class).annotatedWith(Names.named(MAIN_RO_DATA_SOURCE_ID)).toInstance(Mockito.mock(IDBI.class));
                                                                bind(IAopTester.class).to(AopTesterImpl.class).asEagerSingleton();
                                                                bind(TenantInternalApi.class).toInstance(Mockito.mock(TenantInternalApi.class));
                                                                bind(NonEntityDao.class).toInstance(Mockito.mock(NonEntityDao.class));
diff --git a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
index 0569958..f734d68 100644
--- a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2014 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.killbill.commons.locker.memory.MemoryGlobalLocker;
 import org.killbill.commons.locker.mysql.MySqlGlobalLocker;
 import org.killbill.commons.locker.postgresql.PostgreSQLGlobalLocker;
 import org.killbill.notificationq.api.NotificationQueueService;
-import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -87,8 +86,6 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
     @Inject
     protected GlobalLocker locker;
     @Inject
-    protected IDBI idbi;
-    @Inject
     protected TestApiListener eventsListener;
     @Inject
     protected SecurityApi securityApi;