private <T> T callRecurly(
      final AsyncHttpClient.BoundRequestBuilder builder, @Nullable final Class<T> clazz)
      throws IOException, ExecutionException, InterruptedException {
    final Response response =
        builder
            .addHeader("Authorization", "Basic " + key)
            .addHeader("Accept", "application/xml")
            .addHeader("Content-Type", "application/xml; charset=utf-8")
            .execute()
            .get();

    final InputStream in = response.getResponseBodyAsStream();
    try {
      final String payload = convertStreamToString(in);
      if (debug()) {
        log.info("Msg from Recurly API :: {}", payload);
      }

      // Handle errors payload
      if (response.getStatusCode() >= 300) {
        log.warn("Recurly error whilst calling: {}\n{}", response.getUri(), payload);

        if (response.getStatusCode() == 422) {
          final Errors errors;
          try {
            errors = xmlMapper.readValue(payload, Errors.class);
          } catch (Exception e) {
            // 422 is returned for transaction errors (see
            // http://docs.recurly.com/api/transactions/error-codes)
            // as well as bad input payloads
            log.debug("Unable to extract error", e);
            return null;
          }
          throw new TransactionErrorException(errors);
        } else {
          RecurlyAPIError recurlyError = null;
          try {
            recurlyError = xmlMapper.readValue(payload, RecurlyAPIError.class);
          } catch (Exception e) {
            log.debug("Unable to extract error", e);
          }
          throw new RecurlyAPIException(recurlyError);
        }
      }

      if (clazz == null) {
        return null;
      }

      final T obj = xmlMapper.readValue(payload, clazz);
      if (obj instanceof RecurlyObject) {
        ((RecurlyObject) obj).setRecurlyClient(this);
      } else if (obj instanceof RecurlyObjects) {
        final RecurlyObjects recurlyObjects = (RecurlyObjects) obj;
        recurlyObjects.setRecurlyClient(this);

        // Set the RecurlyClient on all objects for later use
        for (final Object object : recurlyObjects) {
          ((RecurlyObject) object).setRecurlyClient(this);
        }

        // Set the total number of records
        final String xRecords = response.getHeader(X_RECORDS_HEADER_NAME);
        if (xRecords != null) {
          recurlyObjects.setNbRecords(Integer.valueOf(xRecords));
        }

        // Set links for pagination
        final String linkHeader = response.getHeader(LINK_HEADER_NAME);
        if (linkHeader != null) {
          final String[] links = PaginationUtils.getLinks(linkHeader);
          recurlyObjects.setStartUrl(links[0]);
          recurlyObjects.setPrevUrl(links[1]);
          recurlyObjects.setNextUrl(links[2]);
        }
      }
      return obj;
    } finally {
      closeStream(in);
    }
  }