)`.)
- val Implementations3_0_0 = Http4s300.Implementations3_0_0
- // Re-export so tests that import OBPAPI3_0_0.Implementations2_2_0 keep compiling
- // (e.g. v4_0_0/AuthenticationTypeValidationTest, ForceErrorValidationTest, JsonSchemaValidationTest).
- val Implementations2_2_0 = Http4s220.Implementations2_2_0
-
- def allResourceDocs = collectResourceDocs(
- OBPAPI2_2_0.allResourceDocs,
- Http4s300.resourceDocs
- )
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
-}
diff --git a/obp-api/src/main/scala/code/api/v3_0_0/custom/APIMethodsCustom300.scala b/obp-api/src/main/scala/code/api/v3_0_0/custom/APIMethodsCustom300.scala
deleted file mode 100644
index 937de2969c..0000000000
--- a/obp-api/src/main/scala/code/api/v3_0_0/custom/APIMethodsCustom300.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-package code.api.v3_0_0.custom
-
-/*
- * CustomAPIMethods300 is retired. Its only endpoint was hard-coded to `null`
- * and its resourceDocs buffer was empty — there is no http4s migration target
- * because nothing was ever served. This stub remains in case `with CustomAPIMethods300`
- * appears in any legacy mixin chain.
- */
-trait CustomAPIMethods300
diff --git a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
deleted file mode 100644
index 831c065761..0000000000
--- a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
+++ /dev/null
@@ -1,6080 +0,0 @@
-package code.api.v3_1_0
-
-
-/*
- * All v3.1.0 endpoints have been migrated to Http4s310. This trait is retained
- * because `with APIMethods310` may still appear in legacy mixin chains.
- * The body is intentionally empty — no Lift Dispatch routes, no ResourceDocs,
- * no `Implementations310` class.
- *
- * Use `Http4s310.Implementations3_1_0` directly (or `OBPAPI3_1_0.Implementations3_1_0`,
- * which is a re-export) for ResourceDoc / route access in tests.
- */
-trait APIMethods310
-
-object APIMethods310 {
- // Re-export so any caller that still imports APIMethods310.Implementations3_1_0 keeps compiling.
- val Implementations3_1_0 = Http4s310.Implementations3_1_0
-}
-
-//package code.api.v3_1_0
-//
-//import scala.language.reflectiveCalls
-//import code.api.Constant
-//import code.api.Constant._
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
-//import code.api.ResourceDocs1_4_0.{MessageDocsSwaggerDefinitions, ResourceDocsAPIMethodsUtil, SwaggerDefinitionsJSON, SwaggerJSONFactory}
-//import code.api.cache.Caching
-//import code.api.util.APIUtil.{getWebUIPropsPairs, _}
-//import code.api.util.ApiRole._
-//import code.api.util.ApiTag._
-//import code.api.util.ErrorMessages.{BankAccountNotFound, _}
-//import code.api.util.ExampleValue._
-//import code.api.util.Glossary
-//import code.api.util.FutureUtil.EndpointContext
-//import code.api.util.NewStyle.HttpCode
-//import code.api.util._
-//import code.api.util.newstyle.{BalanceNewStyle, ViewNewStyle}
-//import code.api.v1_2_1.{JSONFactory, RateLimiting}
-//import code.api.v1_4_0.JSONFactory1_4_0
-//import code.api.v2_0_0.CreateMeetingJson
-//import code.api.v2_1_0._
-//import code.api.v3_0_0.JSONFactory300.createAdapterInfoJson
-//import code.api.v3_0_0.{CreateViewJsonV300, JSONFactory300}
-//import code.api.v3_1_0.JSONFactory310._
-//import code.bankconnectors.rest.RestConnector_vMar2019
-//import code.bankconnectors.{Connector, LocalMappedConnector}
-//import code.consent.{ConsentStatus, Consents, DoobieConsentQueries, MappedConsent}
-//import code.consumer.Consumers
-//import code.entitlement.Entitlement
-//import code.loginattempts.LoginAttempt
-//import code.methodrouting.{MethodRouting, MethodRoutingCommons, MethodRoutingParam}
-//import code.metrics.APIMetrics
-//import code.model._
-//import code.model.dataAccess.{AuthUser, BankAccountCreation}
-//import code.ratelimiting.RateLimitingDI
-//import code.userlocks.UserLocksProvider
-//import code.users.Users
-//import code.util.Helper
-//import code.util.Helper.ObpS
-//import code.views.Views
-//import code.webhook.AccountWebhook
-//import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons}
-//import com.github.dwickern.macros.NameOf.nameOf
-//import com.openbankproject.commons.ExecutionContext.Implicits.global
-//import com.openbankproject.commons.dto.GetProductsParam
-//import com.openbankproject.commons.model._
-//import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, ProductAttributeType, StrongCustomerAuthentication}
-//import com.openbankproject.commons.util.{ApiVersion, ReflectUtils}
-//import net.liftweb.common.{Box, Empty, Full}
-//import com.openbankproject.commons.util.json
-//import org.json4s._
-//import net.liftweb.mapper.By
-//import net.liftweb.util.Helpers.tryo
-//import net.liftweb.util.{Helpers, Props}
-//import org.apache.commons.lang3.{StringUtils, Validate}
-//
-//import java.text.SimpleDateFormat
-//import java.util.UUID
-//import java.util.regex.Pattern
-//import scala.collection.immutable.{List, Nil}
-//import scala.collection.mutable.ArrayBuffer
-//import scala.concurrent.Future
-//
-//trait APIMethods310 {
-// self: RestHelper =>
-//
-// val Implementations3_1_0 = new Implementations310()
-// // note, because RestHelper have a impicit Formats, it is not correct for OBP, so here override it
-// protected implicit override abstract def formats: Formats = CustomJsonFormats.formats
-//
-// class Implementations310 {
-//
-// val implementedInApiVersion = ApiVersion.v3_1_0
-//
-// val resourceDocs = ArrayBuffer[ResourceDoc]()
-// val apiRelations = ArrayBuffer[ApiRelation]()
-// val codeContext = CodeContext(resourceDocs, apiRelations)
-//
-//
-// resourceDocs += ResourceDoc(
-// root,
-// implementedInApiVersion,
-// "root",
-// "GET",
-// "/root",
-// "Get API Info (root)",
-// """Returns information about:
-// |
-// |* API version
-// |* Hosted by information
-// |* Git Commit""",
-// EmptyBody,
-// apiInfoJSON,
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil)
-//
-// lazy val root : OBPEndpoint = {
-// case (Nil | "root" :: Nil) JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (JSONFactory.getApiInfoJSON(OBPAPI3_1_0.version, OBPAPI3_1_0.versionStatus), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getCheckbookOrders,
-// implementedInApiVersion,
-// nameOf(getCheckbookOrders),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/checkbook/orders",
-// "Get Checkbook orders",
-// s"""${mockedDataText(false)}Get all checkbook orders""",
-// EmptyBody,
-// checkbookOrdersJson,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// BankAccountNotFound,
-// InvalidConnectorResponseForGetCheckbookOrdersFuture,
-// UnknownError
-// ),
-// apiTagAccount :: Nil)
-//
-// lazy val getCheckbookOrders : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "checkbook" :: "orders" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-//
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext)
-//
-// (checkbookOrders, callContext)<- Connector.connector.vend.getCheckbookOrders(bankId.value,accountId.value, callContext) map {
-// unboxFullOrFail(_, callContext, InvalidConnectorResponseForGetCheckbookOrdersFuture)
-// }
-// } yield
-// (JSONFactory310.createCheckbookOrdersJson(checkbookOrders), HttpCode.`200`(callContext))
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getStatusOfCreditCardOrder,
-// implementedInApiVersion,
-// nameOf(getStatusOfCreditCardOrder),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/credit_cards/orders",
-// "Get status of Credit Card order ",
-// s"""${mockedDataText(false)}Get status of Credit Card orders
-// |Get all orders
-// |""",
-// EmptyBody,
-// creditCardOrderStatusResponseJson,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// BankAccountNotFound,
-// InvalidConnectorResponseForGetStatusOfCreditCardOrderFuture,
-// UnknownError
-// ),
-// apiTagCard :: Nil)
-//
-// lazy val getStatusOfCreditCardOrder : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "credit_cards" :: "orders" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-//
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext)
-//
-// (checkbookOrders,callContext) <- Connector.connector.vend.getStatusOfCreditCardOrder(bankId.value,accountId.value, callContext) map {
-// unboxFullOrFail(_, callContext, InvalidConnectorResponseForGetStatusOfCreditCardOrderFuture)
-// }
-//
-// } yield
-// (JSONFactory310.createStatisOfCreditCardJson(checkbookOrders), HttpCode.`200`(callContext))
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getTopAPIs,
-// implementedInApiVersion,
-// nameOf(getTopAPIs),
-// "GET",
-// "/management/metrics/top-apis",
-// "Get Top APIs",
-// s"""Get metrics about the most popular APIs. e.g.: total count, response time (in ms), etc.
-// |
-// |Should be able to filter on the following fields
-// |
-// |eg: /management/metrics/top-apis?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5
-// |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount
-// |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions
-// |&verb=GET&anon=false&app_name=MapperPostman
-// |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString
-// |
-// |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString
-// |
-// |3 consumer_id (if null ignore)
-// |
-// |4 user_id (if null ignore)
-// |
-// |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |6 url (if null ignore), note: can not contain '&'.
-// |
-// |7 app_name (if null ignore)
-// |
-// |8 implemented_by_partial_function (if null ignore),
-// |
-// |9 implemented_in_version (if null ignore)
-// |
-// |10 verb (if null ignore)
-// |
-// |11 correlation_id (if null ignore)
-// |
-// |12 duration (if null ignore) non digit chars will be silently omitted
-// |
-// |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%
-// |
-// |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// topApisJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidFilterParameterFormat,
-// GetTopApisError,
-// UnknownError
-// ),
-// apiTagMetric :: Nil,
-// Some(List(canReadMetrics))
-// )
-//
-// lazy val getTopAPIs : OBPEndpoint = {
-// case "management" :: "metrics" :: "top-apis" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-//
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext)
-//
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-//
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-//
-// toApis <- APIMetrics.apiMetrics.vend.getTopApisFuture(obpQueryParams) map {
-// unboxFullOrFail(_, callContext, GetTopApisError)
-// }
-// } yield
-// (JSONFactory310.createTopApisJson(toApis), HttpCode.`200`(callContext))
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getMetricsTopConsumers,
-// implementedInApiVersion,
-// nameOf(getMetricsTopConsumers),
-// "GET",
-// "/management/metrics/top-consumers",
-// "Get Top Consumers",
-// s"""Get metrics about the top consumers of the API usage e.g. total count, consumer_id and app_name.
-// |
-// |Should be able to filter on the following fields
-// |
-// |e.g.: /management/metrics/top-consumers?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5
-// |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount
-// |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions
-// |&verb=GET&anon=false&app_name=MapperPostman
-// |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |&limit=100
-// |
-// |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString
-// |
-// |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString
-// |
-// |3 consumer_id (if null ignore)
-// |
-// |4 user_id (if null ignore)
-// |
-// |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |6 url (if null ignore), note: can not contain '&'.
-// |
-// |7 app_name (if null ignore)
-// |
-// |8 implemented_by_partial_function (if null ignore),
-// |
-// |9 implemented_in_version (if null ignore)
-// |
-// |10 verb (if null ignore)
-// |
-// |11 correlation_id (if null ignore)
-// |
-// |12 duration (if null ignore) non digit chars will be silently omitted
-// |
-// |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%
-// |
-// |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics
-// |
-// |16 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// topConsumersJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidFilterParameterFormat,
-// GetMetricsTopConsumersError,
-// UnknownError
-// ),
-// apiTagMetric :: Nil,
-// Some(List(canReadMetrics))
-// )
-//
-// lazy val getMetricsTopConsumers : OBPEndpoint = {
-// case "management" :: "metrics" :: "top-consumers" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-//
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext)
-//
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-//
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-//
-// topConsumers <- APIMetrics.apiMetrics.vend.getTopConsumersFuture(obpQueryParams) map {
-// unboxFullOrFail(_, callContext, GetMetricsTopConsumersError)
-// }
-//
-// } yield
-// (JSONFactory310.createTopConsumersJson(topConsumers), HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getFirehoseCustomers,
-// implementedInApiVersion,
-// nameOf(getFirehoseCustomers),
-// "GET",
-// "/banks/BANK_ID/firehose/customers",
-// "Get Firehose Customers",
-// s"""
-// |Get Customers that has a firehose View.
-// |
-// |Allows bulk access to customers.
-// |User must have the CanUseFirehoseAtAnyBank Role
-// |
-// |${urlParametersDocument(true, true)}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// customerJSONs,
-// List(AuthenticatedUserIsRequired, CustomerFirehoseNotAllowedOnThisInstance, UserHasMissingRoles, UnknownError),
-// List(apiTagCustomer, apiTagFirehoseData),
-// Some(List(ApiRole.canUseCustomerFirehose, canUseCustomerFirehoseAtAnyBank)))
-//
-// lazy val getFirehoseCustomers : OBPEndpoint = {
-// //get private accounts for all banks
-// case "banks" :: BankId(bankId):: "firehose" :: "customers" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = AccountFirehoseNotAllowedOnThisInstance , cc=callContext) {
-// allowCustomerFirehose
-// }
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, ApiRole.canUseCustomerFirehose :: canUseCustomerFirehoseAtAnyBank :: Nil, callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// allowedParams = List("sort_direction", "limit", "offset", "from_date", "to_date")
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- NewStyle.function.createObpParams(httpParams, allowedParams, callContext)
-// customers <- NewStyle.function.getCustomers(bankId, callContext, obpQueryParams)
-// reqParams = req.params.filterNot(param => allowedParams.contains(param._1))
-// (customersFiltered, callContext) <- if(reqParams.isEmpty) {
-// Future {(customers, callContext)}
-// } else {
-// for{
-// (customerIds, callContext) <- NewStyle.function.getCustomerIdsByAttributeNameValues(bankId, reqParams, callContext)
-// }yield{
-// (customers.filter(customer => customerIds.contains(CustomerId(customer.customerId))),callContext)
-// }
-// }
-// } yield {
-// (JSONFactory300.createCustomersJson(customersFiltered), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getBadLoginStatus,
-// implementedInApiVersion,
-// nameOf(getBadLoginStatus),
-// "GET",
-// "/users/USERNAME/lock-status",
-// "Get User Lock Status",
-// s"""
-// |Get User Login Status.
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// badLoginStatusJson,
-// List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
-// List(apiTagUser),
-// Some(List(canReadUserLockedStatus))
-// )
-//
-// lazy val getBadLoginStatus : OBPEndpoint = {
-// //get private accounts for all banks
-// case "users" :: username:: "lock-status" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadUserLockedStatus, callContext)
-// _ <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map {
-// x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404)
-// }
-// badLoginStatus <- Future { LoginAttempt.getOrCreateBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) }
-// } yield {
-// (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// unlockUser,
-// implementedInApiVersion,
-// nameOf(unlockUser),
-// "PUT",
-// "/users/USERNAME/lock-status",
-// "Unlock the user",
-// s"""
-// |Unlock a User.
-// |
-// |(Perhaps the user was locked due to multiple failed login attempts)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// badLoginStatusJson,
-// List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
-// List(apiTagUser),
-// Some(List(canUnlockUser)))
-//
-// lazy val unlockUser : OBPEndpoint = {
-// //get private accounts for all banks
-// case "users" :: username:: "lock-status" :: Nil JsonPut req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// user <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map {
-// x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404)
-// }
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUnlockUser, callContext)
-// _ <- Future { LoginAttempt.resetBadLoginAttempts(localIdentityProvider,username) }
-// _ <- Future { UserLocksProvider.unlockUser(localIdentityProvider,username) }
-// badLoginStatus <- Future { LoginAttempt.getOrCreateBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) }
-// } yield {
-// (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// callsLimit,
-// implementedInApiVersion,
-// nameOf(callsLimit),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/call-limits",
-// "Set Rate Limits (call limits) per Consumer",
-// s"""
-// |Set the API rate limiting (call limits) per Consumer:
-// |
-// |Rate limits can be set:
-// |
-// |Per Second
-// |Per Minute
-// |Per Hour
-// |Per Week
-// |Per Month
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// callLimitPostJson,
-// callLimitPostJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateRateLimits)))
-//
-// lazy val callsLimit : OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateRateLimits, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CallLimitPostJson ", 400, callContext) {
-// json.extract[CallLimitPostJson]
-// }
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// rateLimiting <- RateLimitingDI.rateLimiting.vend.createOrUpdateConsumerCallLimits(
-// consumerId,
-// postJson.from_date,
-// postJson.to_date,
-// None,
-// None,
-// None,
-// Some(postJson.per_second_call_limit),
-// Some(postJson.per_minute_call_limit),
-// Some(postJson.per_hour_call_limit),
-// Some(postJson.per_day_call_limit),
-// Some(postJson.per_week_call_limit),
-// Some(postJson.per_month_call_limit)) map {
-// unboxFullOrFail(_, callContext, UpdateConsumerError)
-// }
-// } yield {
-// (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getCallsLimit,
-// implementedInApiVersion,
-// nameOf(getCallsLimit),
-// "GET",
-// "/management/consumers/CONSUMER_ID/consumer/call-limits",
-// "Get Rate Limits for a Consumer",
-// s"""
-// |Get Rate Limits per Consumer.
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// callLimitJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateRateLimits)))
-//
-//
-//
-// lazy val getCallsLimit : OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canReadCallLimits, callContext)
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// rateLimit <- Future(RateLimitingUtil.consumerRateLimitState(consumer.consumerId.get).toList)
-// } yield {
-// (createCallLimitJson(consumer, rateLimit), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// checkFundsAvailable,
-// implementedInApiVersion,
-// nameOf(checkFundsAvailable),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/funds-available",
-// "Check Available Funds",
-// """Check Available Funds
-// |Mandatory URL parameters:
-// |
-// |* amount=NUMBER
-// |* currency=STRING
-// |
-// """.stripMargin,
-// EmptyBody,
-// checkFundsAvailableJson,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// BankAccountNotFound,
-// InvalidAmount,
-// InvalidISOCurrencyCode,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2PIIS :: apiTagPsd2 :: Nil)
-//
-// lazy val checkFundsAvailable : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "funds-available" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val amount = "amount"
-// val currency = "currency"
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext)
-// _ <- Helper.booleanToFuture(failMsg = s"$ViewDoesNotPermitAccess + You need the `${(CAN_QUERY_AVAILABLE_FUNDS)}` permission on any your views", cc=callContext) {
-// view.allowed_actions.exists(_ ==CAN_QUERY_AVAILABLE_FUNDS)
-// }
-// httpParams: List[HTTPParam] <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// _ <- Helper.booleanToFuture(failMsg = MissingQueryParams + amount, cc=callContext) {
-// httpParams.exists(_.name == amount)
-// }
-// _ <- Helper.booleanToFuture(failMsg = MissingQueryParams + currency, cc=callContext) {
-// httpParams.exists(_.name == currency)
-// }
-// available <- NewStyle.function.tryons(s"$InvalidAmount", 400, callContext) {
-// val value = httpParams.filter(_.name == amount).map(_.values.head).head
-// new java.math.BigDecimal(value)
-// }
-// _ <- NewStyle.function.isValidCurrencyISOCode(httpParams.filter(_.name == currency).map(_.values.head).head, callContext)
-// _ <- NewStyle.function.moderatedBankAccountCore(account, view, Full(u), callContext)
-// } yield {
-// val ccy = httpParams.filter(_.name == currency).map(_.values.head).head
-// val fundsAvailable = ( view.allowed_actions.exists(_ ==CAN_QUERY_AVAILABLE_FUNDS), account.balance, account.currency) match {
-// case (false, _, _) => "" // 1st condition: MUST have a view can_query_available_funds
-// case (true, _, c) if c != ccy => "no" // 2nd condition: Currency has to be matched
-// case (true, b, _) if b.compare(available) >= 0 => "yes" // We have the vew, the right currency and enough funds
-// case _ => "no"
-// }
-// val availableFundsRequestId = callContext.map(_.correlationId).getOrElse("")
-// (createCheckFundsAvailableJson(fundsAvailable, availableFundsRequestId), HttpCode.`200`(callContext))
-// }
-//
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getConsumer,
-// implementedInApiVersion,
-// nameOf(getConsumer),
-// "GET",
-// "/management/consumers/CONSUMER_ID",
-// "Get Consumer",
-// s"""Get the Consumer specified by CONSUMER_ID.
-// |
-// |""",
-// EmptyBody,
-// consumerJSON,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ConsumerNotFoundByConsumerId,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetConsumers)))
-//
-//
-// lazy val getConsumer: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConsumers, callContext)
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// user <- Users.users.vend.getUserByUserIdFuture(consumer.createdByUserId.get)
-// } yield {
-// (createConsumerJSON(consumer, user), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getConsumersForCurrentUser,
-// implementedInApiVersion,
-// nameOf(getConsumersForCurrentUser),
-// "GET",
-// "/management/users/current/consumers",
-// "Get Consumers (logged in User)",
-// s"""Get the Consumers for logged in User.
-// |
-// |""",
-// EmptyBody,
-// consumersJson310,
-// List(
-// AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsumer)
-// )
-//
-//
-// lazy val getConsumersForCurrentUser: OBPEndpoint = {
-// case "management" :: "users" :: "current" :: "consumers" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// consumer <- Consumers.consumers.vend.getConsumersByUserIdFuture(u.userId)
-// } yield {
-// (createConsumersJson(consumer, Full(u)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getConsumers,
-// implementedInApiVersion,
-// nameOf(getConsumers),
-// "GET",
-// "/management/consumers",
-// "Get Consumers",
-// s"""Get the all Consumers.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |${urlParametersDocument(true, true)}
-// |
-// |""",
-// EmptyBody,
-// consumersJson310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetConsumers))
-// )
-//
-//
-// lazy val getConsumers: OBPEndpoint = {
-// case "management" :: "consumers" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConsumers, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// consumers <- Consumers.consumers.vend.getConsumersFuture(obpQueryParams, callContext)
-// users <- Users.users.vend.getUsersByUserIdsFuture(consumers.map(_.createdByUserId.get))
-// } yield {
-// (createConsumersJson(consumers, users), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// val accountWebHookInfo = s"""Webhooks are used to call external URLs when certain events happen.
-// |
-// |Account Webhooks focus on events around accounts.
-// |
-// |For instance, a webhook could be used to notify an external service if a balance changes on an account.
-// |
-// |This functionality is work in progress! Please note that only implemented trigger is: ${ApiTrigger.onBalanceChange}"""
-//
-//
-// resourceDocs += ResourceDoc(
-// createAccountWebhook,
-// implementedInApiVersion,
-// nameOf(createAccountWebhook),
-// "POST",
-// "/banks/BANK_ID/account-web-hooks",
-// "Create an Account Webhook",
-// s"""Create an Account Webhook
-// |
-// |$accountWebHookInfo
-// |""",
-// accountWebhookPostJson,
-// accountWebhookJson,
-// List(UnknownError),
-// apiTagWebhook :: apiTagBank :: Nil,
-// Some(List(canCreateWebhook))
-// )
-//
-// lazy val createAccountWebhook : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "account-web-hooks" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canCreateWebhook, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountWebhookPostJson "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountWebhookPostJson]
-// }
-// failMsg = IncorrectTriggerName + postJson.trigger_name + ". Possible values are " + ApiTrigger.availableTriggers.sorted.mkString(", ")
-// _ <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// ApiTrigger.valueOf(postJson.trigger_name)
-// }
-// failMsg = s"$InvalidBoolean Possible values of the json field is_active are true or false."
-// isActive <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// postJson.is_active.toBoolean
-// }
-// wh <- AccountWebhook.accountWebhook.vend.createAccountWebhookFuture(
-// bankId = bankId.value,
-// accountId = postJson.account_id,
-// userId = u.userId,
-// triggerName = postJson.trigger_name,
-// url = postJson.url,
-// httpMethod = postJson.http_method,
-// httpProtocol = postJson.http_protocol,
-// isActive = isActive
-// ) map {
-// unboxFullOrFail(_, callContext, CreateWebhookError)
-// }
-// } yield {
-// (createAccountWebhookJson(wh), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// enableDisableAccountWebhook,
-// implementedInApiVersion,
-// nameOf(enableDisableAccountWebhook),
-// "PUT",
-// "/banks/BANK_ID/account-web-hooks",
-// "Enable/Disable an Account Webhook",
-// s"""Enable/Disable an Account Webhook
-// |
-// |
-// |$accountWebHookInfo
-// |""",
-// accountWebhookPutJson,
-// accountWebhookJson,
-// List(UnknownError),
-// apiTagWebhook :: apiTagBank :: Nil,
-// Some(List(canUpdateWebhook))
-// )
-//
-// lazy val enableDisableAccountWebhook : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "account-web-hooks" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateWebhook, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountWebhookPutJson "
-// putJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountWebhookPutJson]
-// }
-// failMsg = s"$InvalidBoolean Possible values of the json field is_active are true or false."
-// isActive <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// putJson.is_active.toBoolean
-// }
-// _ <- AccountWebhook.accountWebhook.vend.getAccountWebhookByIdFuture(putJson.account_webhook_id) map {
-// unboxFullOrFail(_, callContext, WebhookNotFound)
-// }
-// wh <- AccountWebhook.accountWebhook.vend.updateAccountWebhookFuture(
-// accountWebhookId = putJson.account_webhook_id,
-// isActive = isActive
-// ) map {
-// unboxFullOrFail(_, callContext, UpdateWebhookError)
-// }
-// } yield {
-// (createAccountWebhookJson(wh), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getAccountWebhooks,
-// implementedInApiVersion,
-// nameOf(getAccountWebhooks),
-// "GET",
-// "/management/banks/BANK_ID/account-web-hooks",
-// "Get Account Webhooks",
-// s"""Get Account Webhooks.
-// |
-// |Possible custom URL parameters for pagination:
-// |
-// |${urlParametersDocument(false, false)}
-// |* account_id=STRING (if null ignore)
-// |* user_id=STRING (if null ignore)
-// |
-// |
-// |""",
-// EmptyBody,
-// accountWebhooksJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// apiTagWebhook :: apiTagBank :: Nil,
-// Some(List(canGetWebhooks))
-// )
-//
-//
-// lazy val getAccountWebhooks: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) ::"account-web-hooks" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetWebhooks, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// allowedParams = List("limit", "offset", "account_id", "user_id")
-// (obpParams, callContext) <- NewStyle.function.createObpParams(httpParams, allowedParams, callContext)
-// additionalParam = OBPBankId(bankId.value)
-// webhooks <- NewStyle.function.getAccountWebhooks(additionalParam :: obpParams, callContext)
-// } yield {
-// (createAccountWebhooksJson(webhooks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// config,
-// implementedInApiVersion,
-// nameOf(config),
-// "GET",
-// "/config",
-// "Get API Configuration",
-// """Returns information about:
-// |
-// |* The default bank_id
-// |* Akka configuration
-// |* Elastic Search configuration
-// |* Cached functions """,
-// EmptyBody,
-// configurationJSON,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// apiTagApi :: Nil,
-// Some(List(canGetConfig)))
-//
-// lazy val config: OBPEndpoint = {
-// case "config" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConfig, callContext)
-// } yield {
-// (JSONFactory310.getConfigInfoJSON(), HttpCode.`200`(callContext))
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getAdapterInfo,
-// implementedInApiVersion,
-// nameOf(getAdapterInfo),
-// "GET",
-// "/adapter",
-// "Get Adapter Info",
-// s"""Get basic information about the Adapter.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// adapterInfoJsonV300,
-// List(AuthenticatedUserIsRequired,UserHasMissingRoles, UnknownError),
-// List(apiTagApi),
-// Some(List(canGetAdapterInfo))
-// )
-//
-//
-// lazy val getAdapterInfo: OBPEndpoint = {
-// case "adapter" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetAdapterInfo, callContext)
-// (ai,_) <- NewStyle.function.getAdapterInfo(callContext)
-// } yield {
-// (createAdapterInfoJson(ai), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getTransactionByIdForBankAccount,
-// implementedInApiVersion,
-// nameOf(getTransactionByIdForBankAccount),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/transaction",
-// "Get Transaction by Id",
-// s"""Returns one transaction specified by TRANSACTION_ID of the account ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).
-// |
-// |${userAuthenticationMessage(false)}
-// |Authentication is required if the view is not public.
-// |
-// |
-// |""",
-// EmptyBody,
-// transactionJsonV300,
-// List(AuthenticatedUserIsRequired, BankAccountNotFound ,ViewNotFound, UserNoPermissionAccessView, UnknownError),
-// List(apiTagTransaction))
-//
-// lazy val getTransactionByIdForBankAccount : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transactions" :: TransactionId(transactionId) :: "transaction" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- authenticatedAccess(cc)
-// _ <- passesPsd2Pisp(callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), user, callContext)
-// (moderatedTransaction, callContext) <- account.moderatedTransactionFuture(transactionId, view, user, callContext) map {
-// unboxFullOrFail(_, callContext, GetTransactionsException)
-// }
-// (transactionAttributes, callContext) <- NewStyle.function.getTransactionAttributes(
-// bankId,
-// transactionId,
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory300.createTransactionJSON(moderatedTransaction, transactionAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getTransactionRequests,
-// implementedInApiVersion,
-// nameOf(getTransactionRequests),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests",
-// "Get Transaction Requests." ,
-// """Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.
-// |
-// |The VIEW_ID specified must be 'owner' and the user must have access to this view.
-// |
-// |Version 2.0.0 now returns charge information.
-// |
-// |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:
-// |
-// |* Transaction Request Id
-// |* Type
-// |* Status (INITIATED, COMPLETED)
-// |* Challenge (in order to confirm the request)
-// |* From Bank / Account
-// |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)
-// |* Related Transactions
-// |
-// |PSD2 Context: PSD2 requires transparency of charges to the customer.
-// |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.
-// |The customer can proceed with the Transaction by answering the security challenge.
-// |
-// """.stripMargin,
-// EmptyBody,
-// transactionRequestWithChargeJSONs210,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// BankAccountNotFound,
-// UserNoPermissionAccessView,
-// ViewDoesNotPermitAccess,
-// GetTransactionRequestsException,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS))
-//
-// lazy val getTransactionRequests: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-requests" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.isEnabledTransactionRequests(callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkAccountAccessAndGetView(viewId, BankIdAccountId(bankId, accountId), Full(u), callContext)
-// _ <- Helper.booleanToFuture(
-// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})",
-// cc=callContext){
-// view.allowed_actions.exists(_ ==CAN_SEE_TRANSACTION_REQUESTS)
-// }
-// (transactionRequests, callContext) <- Future(Connector.connector.vend.getTransactionRequests210(u, fromAccount, callContext)) map {
-// unboxFullOrFail(_, callContext, GetTransactionRequestsException)
-// }
-// } yield {
-// val json = JSONFactory210.createTransactionRequestJSONs(transactionRequests)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createCustomer,
-// implementedInApiVersion,
-// nameOf(createCustomer),
-// "POST",
-// "/banks/BANK_ID/customers",
-// "Create Customer",
-// s"""
-// |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.
-// |Dates need to be in the format 2013-01-21T23:08:00Z
-// |
-// |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// postCustomerJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateCustomerError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson),
-// Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))
-// )
-// lazy val createCustomer : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canCreateCustomer :: canCreateCustomerAtAnyBank :: Nil, callContext)
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerJsonV310]
-// }
-// _ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants}) not equal the length(${postedData.dob_of_dependants.length }) of dob_of_dependants array", cc=callContext) {
-// postedData.dependants == postedData.dob_of_dependants.length
-// }
-// (customer, callContext) <- NewStyle.function.createCustomer(
-// bankId,
-// postedData.legal_name,
-// postedData.mobile_phone_number,
-// postedData.email,
-// CustomerFaceImage(postedData.face_image.date, postedData.face_image.url),
-// postedData.date_of_birth,
-// postedData.relationship_status,
-// postedData.dependants,
-// postedData.dob_of_dependants,
-// postedData.highest_education_attained,
-// postedData.employment_status,
-// postedData.kyc_status,
-// postedData.last_ok_date,
-// Option(CreditRating(postedData.credit_rating.rating, postedData.credit_rating.source)),
-// Option(CreditLimit(postedData.credit_limit.currency, postedData.credit_limit.amount)),
-// postedData.title,
-// postedData.branch_id,
-// postedData.name_suffix,
-// callContext,
-// )
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getRateLimitingInfo,
-// implementedInApiVersion,
-// nameOf(getRateLimitingInfo),
-// "GET",
-// "/rate-limiting",
-// "Get Rate Limiting Info",
-// s"""Get information about the Rate Limiting setup on this OBP Instance such as:
-// |
-// |Is rate limiting enabled and active?
-// |What backend is used to keep track of the API calls (e.g. REDIS).
-// |
-// |Note: Rate limiting can be set at the Consumer level and also for anonymous calls.
-// |
-// |See the consumer rate limits / call limits endpoints.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// rateLimitingInfoV310,
-// List(UnknownError),
-// List(apiTagApi, apiTagRateLimits))
-//
-//
-// lazy val getRateLimitingInfo: OBPEndpoint = {
-// case "rate-limiting" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// rateLimiting <- NewStyle.function.tryons("", 400, callContext) {
-// val isActive = if (RateLimitingUtil.useConsumerLimits ) true else false
-// RateLimiting(RateLimitingUtil.useConsumerLimits, "REDIS", true, isActive)
-// }
-// } yield {
-// (createRateLimitingInfo(rateLimiting), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getCustomerByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCustomerByCustomerId),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID",
-// "Get Customer by CUSTOMER_ID",
-// s"""Gets the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerWithAttributesJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank)))
-//
-// lazy val getCustomerByCustomerId : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomersAtOneBank, callContext)
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory310.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getCustomerByCustomerNumber,
-// implementedInApiVersion,
-// nameOf(getCustomerByCustomerNumber),
-// "POST",
-// "/banks/BANK_ID/customers/customer-number",
-// "Get Customer by CUSTOMER_NUMBER",
-// s"""Gets the Customer specified by CUSTOMER_NUMBER.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerNumberJsonV310,
-// customerWithAttributesJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomerByCustomerNumber : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "customer-number" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomersAtOneBank, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerNumberJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerNumberJsonV310]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerNumber(postedData.customer_number, bank.bankId, callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customer.customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory310.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createUserAuthContext,
-// implementedInApiVersion,
-// nameOf(createUserAuthContext),
-// "POST",
-// "/users/USER_ID/auth-context",
-// "Create User Auth Context",
-// s"""Create User Auth Context. These key value pairs will be propagated over connector to adapter. Normally used for mapping OBP user and
-// | Bank User/Customer.
-// |${userAuthenticationMessage(true)}
-// |""",
-// postUserAuthContextJson,
-// userAuthContextJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// CreateUserAuthContextError,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canCreateUserAuthContext)))
-//
-// lazy val createUserAuthContext : OBPEndpoint = {
-// case "users" :: userId ::"auth-context" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateUserAuthContext, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextJson]
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key.trim, postedData.value.trim, callContext)
-// } yield {
-// (JSONFactory310.createUserAuthContextJson(userAuthContext), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getUserAuthContexts,
-// implementedInApiVersion,
-// nameOf(getUserAuthContexts),
-// "GET",
-// "/users/USER_ID/auth-context",
-// "Get User Auth Contexts",
-// s"""Get User Auth Contexts for a User.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userAuthContextsJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(canGetUserAuthContext :: Nil)
-// )
-//
-// lazy val getUserAuthContexts : OBPEndpoint = {
-// case "users" :: userId :: "auth-context" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetUserAuthContext, callContext)
-// (_, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContexts, callContext) <- NewStyle.function.getUserAuthContexts(userId, callContext)
-// } yield {
-// (JSONFactory310.createUserAuthContextsJson(userAuthContexts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// deleteUserAuthContexts,
-// implementedInApiVersion,
-// nameOf(deleteUserAuthContexts),
-// "DELETE",
-// "/users/USER_ID/auth-context",
-// "Delete User's Auth Contexts",
-// s"""Delete the Auth Contexts of a User specified by USER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canDeleteUserAuthContext)))
-//
-// lazy val deleteUserAuthContexts : OBPEndpoint = {
-// case "users" :: userId :: "auth-context" :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteUserAuthContext, callContext)
-// (_, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContext, callContext) <- NewStyle.function.deleteUserAuthContexts(userId, callContext)
-// } yield {
-// (Full(userAuthContext), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// deleteUserAuthContextById,
-// implementedInApiVersion,
-// nameOf(deleteUserAuthContextById),
-// "DELETE",
-// "/users/USER_ID/auth-context/USER_AUTH_CONTEXT_ID",
-// "Delete User Auth Context",
-// s"""Delete a User AuthContext of the User specified by USER_AUTH_CONTEXT_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canDeleteUserAuthContext)))
-//
-// lazy val deleteUserAuthContextById : OBPEndpoint = {
-// case "users" :: userId :: "auth-context" :: userAuthContextId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteUserAuthContext, callContext)
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContext, callContext) <- NewStyle.function.deleteUserAuthContextById(user, userAuthContextId, callContext)
-// } yield {
-// (Full(userAuthContext), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createTaxResidence,
-// implementedInApiVersion,
-// nameOf(createTaxResidence),
-// "POST",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/tax-residence",
-// "Create Tax Residence",
-// s"""Create a Tax Residence for a Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postTaxResidenceJsonV310,
-// taxResidenceV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canCreateTaxResidence)))
-//
-// lazy val createTaxResidence : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax-residence" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateTaxResidence, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostTaxResidenceJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostTaxResidenceJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (taxResidence, callContext) <- NewStyle.function.createTaxResidence(customerId, postedData.domain, postedData.tax_number, callContext)
-// } yield {
-// (JSONFactory310.createTaxResidence(taxResidence), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getTaxResidence,
-// implementedInApiVersion,
-// nameOf(getTaxResidence),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/tax-residences",
-// "Get Tax Residences of Customer",
-// s"""Get the Tax Residences of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// taxResidencesJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc))
-//
-// lazy val getTaxResidence : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax-residences" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetTaxResidence, callContext)
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (taxResidences, callContext) <- NewStyle.function.getTaxResidences(customerId, callContext)
-// } yield {
-// (JSONFactory310.createTaxResidences(taxResidences), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// deleteTaxResidence,
-// implementedInApiVersion,
-// nameOf(deleteTaxResidence),
-// "DELETE",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/tax_residencies/TAX_RESIDENCE_ID",
-// "Delete Tax Residence",
-// s"""Delete a Tax Residence of the Customer specified by TAX_RESIDENCE_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc))
-//
-// lazy val deleteTaxResidence : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax_residencies" :: taxResidenceId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteTaxResidence, callContext)
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (taxResidence, callContext) <- NewStyle.function.deleteTaxResidence(taxResidenceId, callContext)
-// } yield {
-// (Full(taxResidence), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// resourceDocs += ResourceDoc(
-// getAllEntitlements,
-// implementedInApiVersion,
-// nameOf(getAllEntitlements),
-// "GET",
-// "/entitlements",
-// "Get all Entitlements",
-// s"""
-// |
-// |Login is required.
-// |
-// |Possible filter on the role field:
-// |
-// |eg: /entitlements?role=${canGetCustomersAtOneBank.toString}
-// |
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// entitlementJSonsV310,
-// List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError),
-// List(apiTagRole, apiTagEntitlement))
-//
-//
-// lazy val getAllEntitlements: OBPEndpoint = {
-// case "entitlements" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetEntitlementsForAnyUserAtAnyBank, callContext)
-// roleName = APIUtil.getHttpRequestUrlParam(cc.url, "role")
-// entitlements <- Entitlement.entitlement.vend.getEntitlementsByRoleFuture(roleName) map {
-// connectorEmptyResponse(_, callContext)
-// }
-// } yield {
-// (JSONFactory310.createEntitlementJsonsV310(entitlements), callContext)
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// createCustomerAddress,
-// implementedInApiVersion,
-// nameOf(createCustomerAddress),
-// "POST",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/address",
-// "Create Address",
-// s"""Create an Address for a Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerAddressJsonV310,
-// customerAddressJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canCreateCustomerAddress)))
-//
-// lazy val createCustomerAddress : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "address" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateCustomerAddress, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerAddressJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerAddressJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (address, callContext) <- NewStyle.function.createCustomerAddress(
-// customerId,
-// postedData.line_1,
-// postedData.line_2,
-// postedData.line_3,
-// postedData.city,
-// postedData.county,
-// postedData.state,
-// postedData.postcode,
-// postedData.country_code,
-// postedData.state,
-// postedData.tags.mkString(","),
-// callContext)
-// } yield {
-// (JSONFactory310.createAddress(address), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerAddress,
-// implementedInApiVersion,
-// nameOf(updateCustomerAddress),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID",
-// "Update the Address of a Customer",
-// s"""Update an Address of the Customer specified by CUSTOMER_ADDRESS_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerAddressJsonV310,
-// customerAddressJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer))
-//
-// lazy val updateCustomerAddress : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: customerAddressId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateCustomer, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerAddressJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerAddressJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (address, callContext) <- NewStyle.function.updateCustomerAddress(
-// customerAddressId,
-// postedData.line_1,
-// postedData.line_2,
-// postedData.line_3,
-// postedData.city,
-// postedData.county,
-// postedData.state,
-// postedData.postcode,
-// postedData.country_code,
-// postedData.state,
-// postedData.tags.mkString(","),
-// callContext)
-// } yield {
-// (JSONFactory310.createAddress(address), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getCustomerAddresses,
-// implementedInApiVersion,
-// nameOf(getCustomerAddresses),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/addresses",
-// "Get Customer Addresses",
-// s"""Get the Addresses of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAddressesJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomerAddress)))
-//
-// lazy val getCustomerAddresses : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomerAddress, callContext)
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customers, callContext) <- NewStyle.function.getCustomerAddress(customerId, callContext)
-// } yield {
-// (JSONFactory310.createAddresses(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// deleteCustomerAddress,
-// implementedInApiVersion,
-// nameOf(deleteCustomerAddress),
-// "DELETE",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID",
-// "Delete Customer Address",
-// s"""Delete an Address of the Customer specified by CUSTOMER_ADDRESS_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canDeleteCustomerAddress)))
-//
-// lazy val deleteCustomerAddress : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: customerAddressId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteCustomerAddress, callContext)
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (address, callContext) <- NewStyle.function.deleteCustomerAddress(customerAddressId, callContext)
-// } yield {
-// (Full(address), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getObpConnectorLoopback,
-// implementedInApiVersion,
-// nameOf(getObpConnectorLoopback),
-// "GET",
-// "/connector/loopback",
-// "Get Connector Status (Loopback)",
-// s"""This endpoint makes a call to the Connector to check the backend transport is reachable. (Deprecated)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// obpApiLoopbackJson,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi, apiTagOAuth, apiTagOIDC))
-//
-// lazy val getObpConnectorLoopback : OBPEndpoint = {
-// case "connector" :: "loopback" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// connectorVersion = code.api.Constant.CONNECTOR.openOrThrowException(s"$MandatoryPropertyIsNotSet The missing props is 'connector'")
-// starConnectorProps = APIUtil.getPropsValue("starConnector_supported_types").openOr("notfound")
-// obpApiLoopback = ObpApiLoopback(
-// connectorVersion ="Unknown",
-// gitCommit ="Unknown",
-// durationTime ="Unknown"
-// )
-// _ = throw new IllegalStateException(s"${NotImplemented}")
-// } yield {
-// (createObpApiLoopbackJson(obpApiLoopback), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// refreshUser,
-// implementedInApiVersion,
-// nameOf(refreshUser),
-// "POST",
-// "/users/USER_ID/refresh",
-// "Refresh User",
-// s""" The endpoint is used for updating the accounts, views, account holders for the user.
-// | As to the Json body, you can leave it as Empty.
-// | This call will get data from backend, no need to prepare the json body in api side.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// refresUserJson,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canRefreshUser))
-// )
-//
-// lazy val refreshUser : OBPEndpoint = {
-// case "users" :: userId :: "refresh" :: Nil JsonPost _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canRefreshUser, callContext)
-// startTime <- Future{Helpers.now}
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// _ <- AuthUser.refreshUser(user, callContext)
-// endTime <- Future{Helpers.now}
-// durationTime = endTime.getTime - startTime.getTime
-// } yield {
-// (createRefreshUserJson(durationTime), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// val productAttributeGeneralInfo =
-// s"""
-// |Product Attributes are used to describe a financial Product with a list of typed key value pairs.
-// |
-// |Each Product Attribute is linked to its Product by PRODUCT_CODE
-// |
-// |
-// """.stripMargin
-//
-// resourceDocs += ResourceDoc(
-// createProductAttribute,
-// implementedInApiVersion,
-// nameOf(createProductAttribute),
-// "POST",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attribute",
-// "Create Product Attribute",
-// s""" Create Product Attribute
-// |
-// |$productAttributeGeneralInfo
-// |
-// |Typical product attributes might be:
-// |
-// |ISIN (for International bonds)
-// |VKN (for German bonds)
-// |REDCODE (markit short code for credit derivative)
-// |LOAN_ID (e.g. used for Anacredit reporting)
-// |
-// |ISSUE_DATE (When the bond was issued in the market)
-// |MATURITY_DATE (End of life time of a product)
-// |TRADABLE
-// |
-// |See [FPML](http://www.fpml.org/) for more examples.
-// |
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productAttributeJson,
-// productAttributeResponseJson,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canCreateProductAttribute))
-// )
-//
-// lazy val createProductAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode:: "attribute" :: Nil JsonPost json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canCreateProductAttribute, callContext)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[ProductAttributeJson]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// productAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// ProductAttributeType.withName(postedData.`type`)
-// }
-//
-// (productAttribute, callContext) <- NewStyle.function.createOrUpdateProductAttribute(
-// BankId(bankId),
-// ProductCode(productCode),
-// None,
-// postedData.name,
-// productAttributeType,
-// postedData.value,
-// None,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createProductAttributeJson(productAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getProductAttribute,
-// implementedInApiVersion,
-// nameOf(getProductAttribute),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID",
-// "Get Product Attribute",
-// s""" Get Product Attribute
-// |
-// |$productAttributeGeneralInfo
-// |
-// |Get one product attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// productAttributeResponseJson,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canGetProductAttribute))
-// )
-//
-// lazy val getProductAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canGetProductAttribute, callContext)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// (productAttribute, callContext) <- NewStyle.function.getProductAttributeById(productAttributeId, callContext)
-//
-// } yield {
-// (createProductAttributeJson(productAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateProductAttribute,
-// implementedInApiVersion,
-// nameOf(updateProductAttribute),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID",
-// "Update Product Attribute",
-// s""" Update Product Attribute.
-// |
-//
-// |$productAttributeGeneralInfo
-// |
-// |Update one Product Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productAttributeJson,
-// productAttributeResponseJson,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canUpdateProductAttribute))
-// )
-//
-// lazy val updateProductAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonPut json -> _ =>{
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canUpdateProductAttribute, callContext)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[ProductAttributeJson]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// productAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// ProductAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getProductAttributeById(productAttributeId, callContext)
-// (productAttribute, callContext) <- NewStyle.function.createOrUpdateProductAttribute(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(productAttributeId),
-// postedData.name,
-// productAttributeType,
-// postedData.value,
-// None,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createProductAttributeJson(productAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteProductAttribute,
-// implementedInApiVersion,
-// nameOf(deleteProductAttribute),
-// "DELETE",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID",
-// "Delete Product Attribute",
-// s""" Delete Product Attribute
-// |
-// |$productAttributeGeneralInfo
-// |
-// |Delete a Product Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// UserHasMissingRoles,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canUpdateProductAttribute)))
-//
-// lazy val deleteProductAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonDelete _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canDeleteProductAttribute, callContext)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// (productAttribute, callContext) <- NewStyle.function.deleteProductAttribute(productAttributeId, callContext)
-// } yield {
-// (Full(productAttribute), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createAccountApplication,
-// implementedInApiVersion,
-// nameOf(createAccountApplication),
-// "POST",
-// "/banks/BANK_ID/account-applications",
-// "Create Account Application",
-// s""" Create Account Application
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// accountApplicationJson,
-// accountApplicationResponseJson,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccountApplication, apiTagAccount))
-//
-// lazy val createAccountApplication : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "account-applications" :: Nil JsonPost json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountApplicationJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountApplicationJson]
-// }
-//
-// illegalProductCodeMsg = s"$InvalidJsonFormat product_code should not be empty."
-// _ <- NewStyle.function.tryons(illegalProductCodeMsg, 400, callContext) {
-// Validate.notBlank(postedData.product_code)
-// }
-//
-// illegalUserIdOrCustomerIdMsg = s"$InvalidJsonFormat User_id and customer_id should not both are empty."
-// _ <- NewStyle.function.tryons(illegalUserIdOrCustomerIdMsg, 400, callContext) {
-// Validate.isTrue(postedData.user_id.isDefined || postedData.customer_id.isDefined)
-// }
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// user <- unboxOptionOBPReturnType(postedData.user_id.map(NewStyle.function.findByUserId(_, callContext)))
-//
-// customer <- unboxOptionOBPReturnType(postedData.customer_id.map(NewStyle.function.getCustomerByCustomerId(_, callContext)))
-//
-// (productAttribute, callContext) <- NewStyle.function.createAccountApplication(
-// productCode = ProductCode(postedData.product_code),
-// userId = postedData.user_id,
-// customerId = postedData.customer_id,
-// callContext = callContext
-// )
-// } yield {
-// (createAccountApplicationJson(productAttribute, user, customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getAccountApplications,
-// implementedInApiVersion,
-// nameOf(getAccountApplications),
-// "GET",
-// "/banks/BANK_ID/account-applications",
-// "Get Account Applications",
-// s"""Get the Account Applications.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// accountApplicationsJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccountApplication, apiTagAccount))
-//
-// lazy val getAccountApplications : OBPEndpoint = {
-// case "banks" :: BankId(bankId) ::"account-applications" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetAccountApplications, callContext)
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// (accountApplications, _) <- NewStyle.function.getAllAccountApplication(callContext)
-// (users, _) <- NewStyle.function.findUsers(accountApplications.map(_.userId), callContext)
-// (customers, _) <- NewStyle.function.findCustomers(accountApplications.map(_.customerId), callContext)
-// } yield {
-// (JSONFactory310.createAccountApplications(accountApplications, users, customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getAccountApplication,
-// implementedInApiVersion,
-// nameOf(getAccountApplication),
-// "GET",
-// "/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID",
-// "Get Account Application by Id",
-// s"""Get the Account Application.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// accountApplicationResponseJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccountApplication, apiTagAccount))
-//
-// lazy val getAccountApplication : OBPEndpoint = {
-// case "banks" :: BankId(bankId) ::"account-applications":: accountApplicationId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// (accountApplication, _) <- NewStyle.function.getAccountApplicationById(accountApplicationId, callContext)
-//
-// userId = Option(accountApplication.userId)
-// customerId = Option(accountApplication.customerId)
-//
-// user <- unboxOptionOBPReturnType(userId.map(NewStyle.function.findByUserId(_, callContext)))
-// customer <- unboxOptionOBPReturnType(customerId.map(NewStyle.function.getCustomerByCustomerId(_, callContext)))
-//
-// } yield {
-// (createAccountApplicationJson(accountApplication, user, customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// updateAccountApplicationStatus,
-// implementedInApiVersion,
-// nameOf(updateAccountApplicationStatus),
-// "PUT",
-// "/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID",
-// "Update Account Application Status",
-// s"""Update an Account Application status
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// accountApplicationUpdateStatusJson,
-// accountApplicationResponseJson,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccountApplication, apiTagAccount)
-// )
-//
-// lazy val updateAccountApplicationStatus : OBPEndpoint = {
-// case "banks" :: BankId(bankId) ::"account-applications" :: accountApplicationId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUpdateAccountApplications, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountApplicationUpdateStatusJson "
-// putJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountApplicationUpdateStatusJson]
-// }
-//
-// failMsg = s"$InvalidJsonFormat status should not be blank."
-// status <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// Validate.notBlank(putJson.status)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-//
-// (accountApplication, _) <- NewStyle.function.getAccountApplicationById(accountApplicationId, callContext)
-//
-// (accountApplication, _) <- NewStyle.function.updateAccountApplicationStatus(accountApplicationId, status, callContext)
-//
-// userId = Option(accountApplication.userId)
-// customerId = Option(accountApplication.customerId)
-//
-// user <- unboxOptionOBPReturnType(userId.map(NewStyle.function.findByUserId(_, callContext)))
-// customer <- unboxOptionOBPReturnType(customerId.map(NewStyle.function.getCustomerByCustomerId(_, callContext)))
-//
-// _ <- status match {
-// case "ACCEPTED" =>
-// for{
-// accountId <- Future{AccountId(UUID.randomUUID().toString)}
-// (_, callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// accountId,
-// accountApplication.productCode.value,
-// "",
-// "EUR",
-// BigDecimal("0"),
-// u.name,
-// "",
-// List.empty,
-// callContext)
-// success <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(bankId, accountId, u, callContext)
-// }yield {
-// success
-// }
-// case _ => Future{""}
-// }
-//
-// } yield {
-// (createAccountApplicationJson(accountApplication, user, customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createProduct,
-// implementedInApiVersion,
-// "createProduct",
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE",
-// "Create Product",
-// s"""Create or Update Product for the Bank.
-// |
-// |
-// |Typical Super Family values / Asset classes are:
-// |
-// |Debt
-// |Equity
-// |FX
-// |Commodity
-// |Derivative
-// |
-// |$productHiearchyAndCollectionNote
-// |
-// |
-// |${userAuthenticationMessage(true) }
-// |
-// |
-// |""",
-// postPutProductJsonV310,
-// productJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canCreateProduct, canCreateProductAtAnyBank))
-// )
-//
-// lazy val createProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostPutProductJsonV310 "
-// product <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostPutProductJsonV310]
-// }
-// (parentProduct,callContext) <- product.parent_product_code.trim.nonEmpty match {
-// case false =>
-// Future((Empty,callContext))
-// case true =>
-// NewStyle.function.getProduct(bankId, ProductCode(product.parent_product_code), callContext).map(product=> (Full(product._1), callContext))
-// }
-// (success, callContext) <- NewStyle.function.createOrUpdateProduct(
-// bankId = bankId.value,
-// code = productCode.value,
-// parentProductCode = parentProduct.map(_.code.value).toOption,
-// name = product.name,
-// category = product.category,
-// family = product.family,
-// superFamily = product.super_family,
-// moreInfoUrl = product.more_info_url,
-// termsAndConditionsUrl = null,
-// details = product.details,
-// description = product.description,
-// metaLicenceId = product.meta.license.id,
-// metaLicenceName = product.meta.license.name,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createProductJson(success), HttpCode.`201`(callContext))
-// }
-//
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getProduct,
-// implementedInApiVersion,
-// "getProduct",
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE",
-// "Get Bank Product",
-// s"""Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including:
-// |
-// |* Name
-// |* Code
-// |* Parent Product Code
-// |* Category
-// |* Family
-// |* Super Family
-// |* More info URL
-// |* Description
-// |* Terms and Conditions
-// |* License the data under this endpoint is released under
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (product, callContext)<- NewStyle.function.getProduct(bankId, productCode, callContext)
-// (productAttributes, callContext) <- NewStyle.function.getProductAttributesByBankAndCode(bankId, productCode, callContext)
-// } yield {
-// (JSONFactory310.createProductJson(product, productAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getProductTree,
-// implementedInApiVersion,
-// nameOf(getProductTree),
-// "GET",
-// "/banks/BANK_ID/product-tree/PRODUCT_CODE",
-// "Get Product Tree",
-// s"""Returns information about a particular financial product specified by BANK_ID and PRODUCT_CODE
-// |and it's parent product(s) recursively as specified by parent_product_code.
-// |
-// |Each product includes the following information.
-// |
-// |* Name
-// |* Code
-// |* Parent Product Code
-// |* Category
-// |* Family
-// |* Super Family
-// |* More info URL
-// |* Description
-// |* Terms and Conditions
-// |* License: The licence under which this product data is released. Licence can be an Open Data licence such as Open Data Commons Public Domain Dedication and License (PDDL) or Copyright etc.
-// |
-// |
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// childProductTreeJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProductTree: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "product-tree" :: ProductCode(productCode) :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getProduct(bankId, productCode, callContext)
-// (products,callContext) <- NewStyle.function.getProductTree(bankId, productCode, callContext)
-// } yield {
-// (JSONFactory310.createProductTreeJson(products, productCode.value), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getProducts,
-// implementedInApiVersion,
-// "getProducts",
-// "GET",
-// "/banks/BANK_ID/products",
-// "Get Products",
-// s"""Returns information about the financial products offered by a bank specified by BANK_ID including:
-// |
-// |* Name
-// |* Code
-// |* Parent Product Code
-// |* Category
-// |* Family
-// |* Super Family
-// |* More info URL
-// |* Description
-// |* Terms and Conditions
-// |* License the data under this endpoint is released under
-// |
-// |Can filter with attributes name and values.
-// |URL params example: /banks/some-bank-id/products?&limit=50&offset=1
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productsJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProducts : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2))
-// (products, callContext) <- NewStyle.function.getProducts(bankId, params, callContext)
-// } yield {
-// (JSONFactory310.createProductsJson(products), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-//
-//
-//
-//
-// val accountAttributeGeneralInfo =
-// s"""
-// |Account Attributes are used to describe a financial Product with a list of typed key value pairs.
-// |
-// |Each Account Attribute is linked to its Account by ACCOUNT_ID
-// |
-// |
-// """.stripMargin
-//
-// resourceDocs += ResourceDoc(
-// createAccountAttribute,
-// implementedInApiVersion,
-// nameOf(createAccountAttribute),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attribute",
-// "Create Account Attribute",
-// s""" Create Account Attribute
-// |
-// |$accountAttributeGeneralInfo
-// |
-// |Typical account attributes might be:
-// |
-// |ISIN (for International bonds)
-// |VKN (for German bonds)
-// |REDCODE (markit short code for credit derivative)
-// |LOAN_ID (e.g. used for Anacredit reporting)
-// |
-// |ISSUE_DATE (When the bond was issued in the market)
-// |MATURITY_DATE (End of life time of a product)
-// |TRADABLE
-// |
-// |See [FPML](http://www.fpml.org/) for more examples.
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// accountAttributeJson,
-// accountAttributeResponseJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute),
-// Some(List(canCreateAccountAttributeAtOneBank))
-// )
-//
-// lazy val createAccountAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "accounts" :: accountId :: "products" :: productCode :: "attribute" :: Nil JsonPost json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountAttributeJson]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AccountAttributeType.DOUBLE}(2012-04-23), ${AccountAttributeType.STRING}(TAX_NUMBER), ${AccountAttributeType.INTEGER}(123) and ${AccountAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// accountAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// AccountAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(BankId(bankId), AccountId(accountId), callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, ApiRole.canCreateAccountAttributeAtOneBank, callContext)
-// (products, callContext) <-NewStyle.function.getProduct(BankId(bankId), ProductCode(productCode), callContext)
-// (accountAttribute, callContext) <- NewStyle.function.createOrUpdateAccountAttribute(
-// BankId(bankId),
-// AccountId(accountId),
-// ProductCode(productCode),
-// None,
-// postedData.name,
-// accountAttributeType,
-// postedData.value,
-// postedData.product_instance_code,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createAccountAttributeJson(accountAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateAccountAttribute,
-// implementedInApiVersion,
-// nameOf(updateAccountAttribute),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attributes/ACCOUNT_ATTRIBUTE_ID",
-// "Update Account Attribute",
-// s""" Update Account Attribute
-// |
-// |$accountAttributeGeneralInfo
-// |
-// |Typical account attributes might be:
-// |
-// |ISIN (for International bonds)
-// |VKN (for German bonds)
-// |REDCODE (markit short code for credit derivative)
-// |LOAN_ID (e.g. used for Anacredit reporting)
-// |
-// |ISSUE_DATE (When the bond was issued in the market)
-// |MATURITY_DATE (End of life time of a product)
-// |TRADABLE
-// |
-// |See [FPML](http://www.fpml.org/) for more examples.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// accountAttributeJson,
-// accountAttributeResponseJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute),
-// Some(List(canUpdateAccountAttribute))
-// )
-//
-// lazy val updateAccountAttribute : OBPEndpoint = {
-// case "banks" :: bankId :: "accounts" :: accountId :: "products" :: productCode :: "attributes" :: accountAttributeId :: Nil JsonPut json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canUpdateAccountAttribute, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AccountAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountAttributeJson]
-// }
-//
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AccountAttributeType.DOUBLE}(2012-04-23), ${AccountAttributeType.STRING}(TAX_NUMBER), ${AccountAttributeType.INTEGER}(123) and ${AccountAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// accountAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// AccountAttributeType.withName(postedData.`type`)
-// }
-//
-// (_, callContext) <- NewStyle.function.getBankAccount(BankId(bankId), AccountId(accountId), callContext)
-// (_, callContext) <- NewStyle.function.getProduct(BankId(bankId), ProductCode(productCode), callContext)
-// (_, callContext) <- NewStyle.function.getAccountAttributeById(accountAttributeId, callContext)
-//
-//
-// (accountAttribute, callContext) <- NewStyle.function.createOrUpdateAccountAttribute(
-// BankId(bankId),
-// AccountId(accountId),
-// ProductCode(productCode),
-// Some(accountAttributeId),
-// postedData.name,
-// accountAttributeType,
-// postedData.value,
-// postedData.product_instance_code,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createAccountAttributeJson(accountAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-//
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// createProductCollection,
-// implementedInApiVersion,
-// nameOf(createProductCollection),
-// "PUT",
-// "/banks/BANK_ID/product-collections/COLLECTION_CODE",
-// "Create Product Collection",
-// s"""Create or Update a Product Collection at the Bank.
-// |
-// |Use Product Collections to create Product "Baskets", "Portfolios", "Indices", "Collections", "Underlyings-lists", "Buckets" etc. etc.
-// |
-// |There is a many to many relationship between Products and Product Collections:
-// |
-// |* A Product can exist in many Collections
-// |
-// |* A Collection can contain many Products.
-// |
-// |A collection has collection code, one parent Product and one or more child Products.
-// |
-// |
-// |$productHiearchyAndCollectionNote
-//
-// |${userAuthenticationMessage(true) }
-// |
-// |
-// |""",
-// putProductCollectionsV310,
-// productCollectionsJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProductCollection, apiTagProduct),
-// Some(List(canMaintainProductCollection))
-// )
-//
-// lazy val createProductCollection: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "product-collections" :: collectionCode :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canMaintainProductCollection, callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutProductCollectionsV310 "
-// product <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutProductCollectionsV310]
-// }
-// (products, callContext) <- NewStyle.function.getProducts(bankId, Nil, callContext)
-// _ <- Helper.booleanToFuture(ProductNotFoundByProductCode + " {" + (product.parent_product_code :: product.children_product_codes).mkString(", ") + "}", cc=callContext) {
-// val existingCodes = products.map(_.code.value)
-// val codes = product.parent_product_code :: product.children_product_codes
-// codes.forall(i => existingCodes.contains(i))
-// }
-// (productCollection, callContext) <- NewStyle.function.getOrCreateProductCollection(
-// collectionCode,
-// List(product.parent_product_code),
-// callContext
-// )
-// (productCollectionItems, callContext) <- NewStyle.function.getOrCreateProductCollectionItems(
-// collectionCode,
-// product.children_product_codes,
-// callContext
-// )
-// } yield {
-// (createProductCollectionsJson(productCollection, productCollectionItems), HttpCode.`201`(callContext))
-// }
-//
-// }
-// }
-//
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getProductCollection,
-// implementedInApiVersion,
-// nameOf(getProductCollection),
-// "GET",
-// "/banks/BANK_ID/product-collections/COLLECTION_CODE",
-// "Get Product Collection",
-// s"""Returns information about the financial Product Collection specified by BANK_ID and COLLECTION_CODE:
-// |
-// """,
-// EmptyBody,
-// productCollectionJsonTreeV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProductCollection, apiTagProduct)
-// )
-//
-// lazy val getProductCollection : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "product-collections" :: collectionCode :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (payload, callContext) <- NewStyle.function.getProductCollectionItemsTree(collectionCode, bankId.value, callContext)
-// } yield {
-// (createProductCollectionsTreeJson(payload), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// // Delete Branch
-// private[this] val deleteBranchEntitlementsRequiredForSpecificBank = CanDeleteBranch :: Nil
-// private[this] val deleteBranchEntitlementsRequiredForAnyBank = CanDeleteBranchAtAnyBank :: Nil
-// private[this] val deleteBranchEntitlementsRequiredText = UserHasMissingRoles + deleteBranchEntitlementsRequiredForSpecificBank.mkString(" and ") + " entitlements are required OR " + deleteBranchEntitlementsRequiredForAnyBank.mkString(" and ")
-//
-// resourceDocs += ResourceDoc(
-// deleteBranch,
-// implementedInApiVersion,
-// nameOf(deleteBranch),
-// "DELETE",
-// "/banks/BANK_ID/branches/BRANCH_ID",
-// "Delete Branch",
-// s"""Delete Branch from given Bank.
-// |
-// |${userAuthenticationMessage(true) }
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InsufficientAuthorisationToDeleteBranch,
-// UnknownError
-// ),
-// List(apiTagBranch),
-// Some(List(canDeleteBranch,canDeleteBranchAtAnyBank))
-// )
-//
-// lazy val deleteBranch: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "branches" :: BranchId(branchId) :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// allowedEntitlements = canDeleteBranch ::canDeleteBranchAtAnyBank:: Nil
-// allowedEntitlementsTxt = allowedEntitlements.mkString(" or ")
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = UserHasMissingRoles + allowedEntitlementsTxt)(bankId.value, u.userId, allowedEntitlements, callContext)
-// (branch, callContext) <- NewStyle.function.getBranch(bankId, branchId, callContext)
-// (result, callContext) <- NewStyle.function.deleteBranch(branch, callContext)
-// } yield {
-// (Full(result), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createMeeting,
-// implementedInApiVersion,
-// "createMeeting",
-// "POST",
-// "/banks/BANK_ID/meetings",
-// "Create Meeting (video conference/call)",
-// """Create Meeting: Initiate a video conference/call with the bank.
-// |
-// |The Meetings resource contains meta data about video/other conference sessions
-// |
-// |provider_id determines the provider of the meeting / video chat service. MUST be url friendly (no spaces).
-// |
-// |purpose_id explains the purpose of the chat. onboarding | mortgage | complaint etc. MUST be url friendly (no spaces).
-// |
-// |Login is required.
-// |
-// |This call is **experimental**. Currently staff_user_id is not set. Further calls will be needed to correctly set this.
-// """.stripMargin,
-// createMeetingJsonV310,
-// meetingJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
-//
-// lazy val createMeeting: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CreateMeetingJson "
-// createMeetingJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CreateMeetingJsonV310]
-// }
-// // These following are only for `tokbox` stuff, for now, just ignore it.
-// // _ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(MeetingApiKeyNotConfigured, 403)
-// // _ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(MeetingApiSecretNotConfigured, 403)
-// // u <- cc.user ?~! AuthenticatedUserIsRequired
-// // _ <- tryo(assert(isValidID(bankId.value)))?~! InvalidBankIdFormat
-// // (bank, callContext) <- Bank(bankId, Some(cc)) ?~! BankNotFound
-// // postedData <- tryo {json.extract[CreateMeetingJson]} ?~! InvalidJsonFormat
-// // now = Calendar.getInstance().getTime()
-// // sessionId <- tryo{code.opentok.OpenTokUtil.getSession.getSessionId()}
-// // customerToken <- tryo{code.opentok.OpenTokUtil.generateTokenForPublisher(60)}
-// // staffToken <- tryo{code.opentok.OpenTokUtil.generateTokenForModerator(60)}
-// //The following three are just used for Tokbox
-// sessionId = ""
-// customerToken =""
-// staffToken = ""
-//
-// creator = ContactDetails(createMeetingJson.creator.name,createMeetingJson.creator.mobile_phone,createMeetingJson.creator.email_address)
-// invitees = createMeetingJson.invitees.map(
-// invitee =>
-// Invitee(
-// ContactDetails(invitee.contact_details.name, invitee.contact_details.mobile_phone,invitee.contact_details.email_address),
-// invitee.status))
-// (meeting, callContext) <- NewStyle.function.createMeeting(
-// bank.bankId,
-// u,
-// u,
-// createMeetingJson.provider_id,
-// createMeetingJson.purpose_id,
-// createMeetingJson.date,
-// sessionId,
-// customerToken,
-// staffToken,
-// creator,
-// invitees,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createMeetingJson(meeting), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getMeetings,
-// implementedInApiVersion,
-// "getMeetings",
-// "GET",
-// "/banks/BANK_ID/meetings",
-// "Get Meetings",
-// """Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
-// |
-// |The actual conference/chats are handled by external services.
-// |
-// |Login is required.
-// |
-// |This call is **experimental** and will require further authorisation in the future.
-// """.stripMargin,
-// EmptyBody,
-// meetingsJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError),
-// List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
-//
-// lazy val getMeetings: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (meetings, callContext) <- NewStyle.function.getMeetings(bank.bankId, u, callContext)
-// } yield {
-// (createMeetingsJson(meetings), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getMeeting,
-// implementedInApiVersion,
-// "getMeeting",
-// "GET",
-// "/banks/BANK_ID/meetings/MEETING_ID",
-// "Get Meeting",
-// """Get Meeting specified by BANK_ID / MEETING_ID
-// |Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
-// |
-// |The actual conference/chats are handled by external services.
-// |
-// |Login is required.
-// |
-// |This call is **experimental** and will require further authorisation in the future.
-// """.stripMargin,
-// EmptyBody,
-// meetingJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// MeetingNotFound,
-// UnknownError
-// ),
-// List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
-//
-// lazy val getMeeting: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "meetings" :: meetingId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (meeting, callContext) <- NewStyle.function.getMeeting(bank.bankId, u, meetingId, callContext)
-// } yield {
-// (JSONFactory310.createMeetingJson(meeting), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getServerJWK,
-// implementedInApiVersion,
-// "getServerJWK",
-// "GET",
-// "/certs",
-// "Get JSON Web Key (JWK)",
-// """Get the server's public JSON Web Key (JWK) set and certificate chain.
-// | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects.
-// |
-// """.stripMargin,
-// EmptyBody,
-// severJWK,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val getServerJWK: OBPEndpoint = {
-// case "certs" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// } yield {
-// (parse(CertificateUtil.convertRSAPublicKeyToAnRSAJWK()), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getMessageDocsSwagger,
-// implementedInApiVersion,
-// nameOf(getMessageDocsSwagger),
-// "GET",
-// "/message-docs/CONNECTOR/swagger2.0",
-// "Get Message Docs Swagger",
-// """
-// |This endpoint provides example message docs in swagger format.
-// |It is only relavent for REST Connectors.
-// |
-// |This endpoint can be used by the developer building a REST Adapter that connects to the Core Banking System (CBS).
-// |That is, the Adapter developer can use the Swagger surfaced here to build the REST APIs that the OBP REST connector will call to consume CBS services.
-// |
-// |i.e.:
-// |
-// |OBP API (Core OBP API code) -> OBP REST Connector (OBP REST Connector code) -> OBP REST Adapter (Adapter developer code) -> CBS (Main Frame)
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(UnknownError),
-// List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)
-// )
-//
-// lazy val getMessageDocsSwagger: OBPEndpoint = {
-// case "message-docs" :: restConnectorVersion ::"swagger2.0" :: Nil JsonGet _ => {
-// val (resourceDocTags, partialFunctions, locale, contentParam, apiCollectionIdParam) = ResourceDocsAPIMethodsUtil.getParams()
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// cacheKey = APIUtil.createResourceDocCacheKey(
-// None,
-// restConnectorVersion,
-// resourceDocTags,
-// partialFunctions,
-// locale,
-// contentParam,
-// apiCollectionIdParam,
-// None
-// )
-// cacheValueFromRedis = Caching.getStaticSwaggerDocCache(cacheKey)
-// swaggerJValue <- if (cacheValueFromRedis.isDefined) {
-// NewStyle.function.tryons(s"$UnknownError Can not convert internal swagger file from cache.", 400, cc.callContext) {
-// json.parse(cacheValueFromRedis.get)
-// }
-// } else {
-// NewStyle.function.tryons(s"$UnknownError Can not convert internal swagger file.", 400, cc.callContext) {
-// val convertedToResourceDocs = RestConnector_vMar2019.messageDocs.map(toResourceDoc).toList
-// val resourceDocListFiltered = ResourceDocsAPIMethodsUtil.filterResourceDocs(convertedToResourceDocs, resourceDocTags, partialFunctions)
-// val resourceDocJsonList = JSONFactory1_4_0.createResourceDocsJson(resourceDocListFiltered, true, None).resource_docs
-// val swaggerResourceDoc = SwaggerJSONFactory.createSwaggerResourceDoc(resourceDocJsonList, ApiVersion.v3_1_0)
-// //For this connector swagger, it shares some basic fields with api swagger, eg: BankId, AccountId. So it need to merge here.
-// val allSwaggerDefinitionCaseClasses = MessageDocsSwaggerDefinitions.allFields ++ SwaggerDefinitionsJSON.allFields
-// val jsonAST = SwaggerJSONFactory.loadDefinitions(resourceDocJsonList, allSwaggerDefinitionCaseClasses)
-// val swaggerDocJsonJValue = Extraction.decompose(swaggerResourceDoc) merge jsonAST
-// val jsonString = json.compactRender(swaggerDocJsonJValue)
-// Caching.setStaticSwaggerDocCache(cacheKey, jsonString)
-// swaggerDocJsonJValue
-// }
-// }
-// } yield {
-// // Merge both results and return
-// (swaggerJValue, HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-// val generalObpConsentText : String =
-// s"""
-// |
-// |An OBP Consent allows the holder of the Consent to call one or more endpoints.
-// |
-// |Consents must be created and authorisied using SCA (Strong Customer Authentication).
-// |
-// |That is, Consents can be created by an authorised User via the OBP REST API but they must be confirmed via an out of band (OOB) mechanism such as a code sent to a mobile phone.
-// |
-// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(", ") }.
-// |
-// |Each Consent is bound to a consumer i.e. you need to identify yourself over request header value Consumer-Key.
-// |For example:
-// |GET /obp/v4.0.0/users/current HTTP/1.1
-// |Host: 127.0.0.1:8080
-// |Consent-JWT: eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEFueVVzZXIiLCJiYW5rX2lkIjoiIn
-// |1dLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIzNDc1MDEzZi03YmY5LTQyNj
-// |EtOWUxYy0xZTdlNWZjZTJlN2UiLCJhdWQiOiI4MTVhMGVmMS00YjZhLTQyMDUtYjExMi1lNDVmZDZmNGQzYWQiLCJuYmYiOjE1ODA3NDE2NjcsIml
-// |zcyI6Imh0dHA6XC9cLzEyNy4wLjAuMTo4MDgwIiwiZXhwIjoxNTgwNzQ1MjY3LCJpYXQiOjE1ODA3NDE2NjcsImp0aSI6ImJkYzVjZTk5LTE2ZTY
-// |tNDM4Yi1hNjllLTU3MTAzN2RhMTg3OCIsInZpZXdzIjpbXX0.L3fEEEhdCVr3qnmyRKBBUaIQ7dk1VjiFaEBW8hUNjfg
-// |
-// |Consumer-Key: ejznk505d132ryomnhbx1qmtohurbsbb0kijajsk
-// |cache-control: no-cache
-// |
-// |Maximum time to live of the token is specified over props value consents.max_time_to_live. In case isn't defined default value is 3600 seconds.
-// |
-// |Example of POST JSON:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "email": "eveline@example.com",
-// | "valid_from": "2020-02-07T08:43:34Z",
-// | "time_to_live": 3600
-// |}
-// |Please note that only optional fields are: consumer_id, valid_from and time_to_live.
-// |In case you omit they the default values are used:
-// |consumer_id = consumer of current user
-// |valid_from = current time
-// |time_to_live = consents.max_time_to_live
-// |
-// """.stripMargin
-//
-// resourceDocs += ResourceDoc(
-// createConsentEmail,
-// implementedInApiVersion,
-// nameOf(createConsentEmail),
-// "POST",
-// "/banks/BANK_ID/my/consents/EMAIL",
-// "Create Consent (EMAIL)",
-// s"""
-// |
-// |This endpoint starts the process of creating a Consent.
-// |
-// |The Consent is created in an ${ConsentStatus.INITIATED} state.
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
-// |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
-// |
-// |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
-// |
-// |$generalObpConsentText
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Example 1:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "phone_number": "+49 170 1234567"
-// |}
-// |
-// |Please note that consumer_id is optional field
-// |Example 2:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "phone_number": "+49 170 1234567"
-// |}
-// |
-// |Please note if everything=false you need to explicitly specify views and entitlements
-// |Example 3:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "phone_number": "+49 170 1234567"
-// |}
-// |
-// |""",
-// postConsentEmailJsonV310,
-// consentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// resourceDocs += ResourceDoc(
-// createConsentSms,
-// implementedInApiVersion,
-// nameOf(createConsentSms),
-// "POST",
-// "/banks/BANK_ID/my/consents/SMS",
-// "Create Consent (SMS)",
-// s"""
-// |
-// |This endpoint starts the process of creating a Consent.
-// |
-// |The Consent is created in an ${ConsentStatus.INITIATED} state.
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
-// |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
-// |
-// |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
-// |
-// |$generalObpConsentText
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Example 1:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "email": "eveline@example.com"
-// |}
-// |
-// |Please note that consumer_id is optional field
-// |Example 2:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "email": "eveline@example.com"
-// |}
-// |
-// |Please note if everything=false you need to explicitly specify views and entitlements
-// |Example 3:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "email": "eveline@example.com"
-// |}
-// |
-// |""",
-// postConsentPhoneJsonV310,
-// consentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// MissingPropsValueAtThisInstance,
-// SmsServerNotResponding,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// resourceDocs += ResourceDoc(
-// createConsentImplicit,
-// implementedInApiVersion,
-// nameOf(createConsentImplicit),
-// "POST",
-// "/banks/BANK_ID/my/consents/IMPLICIT",
-// "Create Consent (IMPLICIT)",
-// s"""
-// |
-// |This endpoint starts the process of creating a Consent.
-// |
-// |The Consent is created in an ${ConsentStatus.INITIATED} state.
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
-// |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
-// |
-// |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
-// |
-// |$generalObpConsentText
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Example 1:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// |}
-// |
-// |Please note that consumer_id is optional field
-// |Example 2:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// |}
-// |
-// |Please note if everything=false you need to explicitly specify views and entitlements
-// |Example 3:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// |}
-// |
-// |""",
-// postConsentImplicitJsonV310,
-// consentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// MissingPropsValueAtThisInstance,
-// SmsServerNotResponding,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// lazy val createConsentEmail = createConsent
-// lazy val createConsentSms = createConsent
-// lazy val createConsentImplicit = createConsent
-//
-// lazy val createConsent : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "consents" :: scaMethod :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
-// List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod)
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
-// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentBodyCommonJson]
-// }
-// maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
-// _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){
-// consentJson.time_to_live match {
-// case Some(ttl) => ttl <= maxTimeToLive
-// case _ => true
-// }
-// }
-// requestedEntitlements = consentJson.entitlements
-// myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId)
-// _ <- Helper.booleanToFuture(RolesAllowedInConsent, cc=callContext){
-// requestedEntitlements.forall(
-// re => myEntitlements.getOrElse(Nil).exists(
-// e => e.roleName == re.role_name && e.bankId == re.bank_id
-// )
-// )
-// }
-// requestedViews = consentJson.views
-// (_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
-// _ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc=callContext){
-// requestedViews.forall(
-// rv => assignedViews.exists{
-// e =>
-// e.view_id == rv.view_id &&
-// e.bank_id == rv.bank_id &&
-// e.account_id == rv.account_id
-// }
-// )
-// }
-// (consumerId, applicationText, consumer) <- consentJson.consumer_id match {
-// case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map {
-// c => (Some(c.consumerId.get), c.description, Some(c))
-// }
-// case None => Future(None, "Any application", None)
-// }
-//
-//
-// challengeAnswer = Props.mode match {
-// case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
-// case _ => SecureRandomUtil.numeric()
-// }
-// createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None, consumer)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// consentJWT =
-// Consent.createConsentJWT(
-// user,
-// consentJson,
-// createdConsent.secret,
-// createdConsent.consentId,
-// consumerId,
-// consentJson.valid_from,
-// consentJson.time_to_live.getOrElse(3600),
-// None
-// )
-// _ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// validUntil = Helper.calculateValidTo(consentJson.valid_from, consentJson.time_to_live.getOrElse(3600))
-// _ <- Future(Consents.consentProvider.vend.setValidUntil(createdConsent.consentId, validUntil)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// //we need to check `skip_consent_sca_for_consumer_id_pairs` props, to see if we really need the SCA flow.
-// //this is from callContext
-// grantorConsumerId = callContext.map(_.consumer.toOption.map(_.consumerId.get)).flatten.getOrElse("Unknown")
-// //this is from json body
-// granteeConsumerId = consentJson.consumer_id.getOrElse("Unknown")
-//
-// shouldSkipConsentScaForConsumerIdPair = APIUtil.skipConsentScaForConsumerIdPairs.contains(
-// APIUtil.ConsumerIdPair(
-// grantorConsumerId,
-// granteeConsumerId
-// ))
-// mappedConsent <- if (shouldSkipConsentScaForConsumerIdPair) {
-// Future{
-// MappedConsent.find(By(MappedConsent.mConsentId, createdConsent.consentId)).map(_.mStatus(ConsentStatus.ACCEPTED.toString).saveMe()).head
-// }
-// } else {
-// val challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText"
-// scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email
-// for{
-// failMsg <- Future {s"$InvalidJsonFormat The Json body should be the $PostConsentEmailJsonV310"}
-// postConsentEmailJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentEmailJsonV310]
-// }
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.EMAIL,
-// postConsentEmailJson.email,
-// Some("OBP Consent Challenge"),
-// challengeText,
-// callContext
-// )
-// } yield createdConsent
-// case v if v == StrongCustomerAuthentication.SMS.toString =>
-// for {
-// failMsg <- Future {
-// s"$InvalidJsonFormat The Json body should be the $PostConsentPhoneJsonV310"
-// }
-// postConsentPhoneJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentPhoneJsonV310]
-// }
-// phoneNumber = postConsentPhoneJson.phone_number
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.SMS,
-// phoneNumber,
-// None,
-// challengeText,
-// callContext
-// )
-// } yield createdConsent
-// case v if v == StrongCustomerAuthentication.IMPLICIT.toString =>
-// for {
-// (consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
-// status <- consentImplicitSCA.scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
-// NewStyle.function.sendCustomerNotification (
-// StrongCustomerAuthentication.EMAIL,
-// consentImplicitSCA.recipient,
-// Some ("OBP Consent Challenge"),
-// challengeText,
-// callContext
-// )
-// case v if v == StrongCustomerAuthentication.SMS =>
-// NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.SMS,
-// consentImplicitSCA.recipient,
-// None,
-// challengeText,
-// callContext
-// )
-// case _ => Future {
-// "Success"
-// }
-// }} yield {
-// createdConsent
-// }
-// case _ =>Future{createdConsent}}
-// }
-// } yield {
-// (ConsentJsonV310(createdConsent.consentId, consentJWT, createdConsent.status), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// answerConsentChallenge,
-// implementedInApiVersion,
-// nameOf(answerConsentChallenge),
-// "POST",
-// "/banks/BANK_ID/consents/CONSENT_ID/challenge",
-// "Answer Consent Challenge",
-// s"""
-// |
-// |$generalObpConsentText
-// |
-// |
-// |This endpoint is used to confirm a Consent previously created.
-// |
-// |The User must supply a code that was sent out of band (OOB) for example via an SMS.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PostConsentChallengeJsonV310(answer = "12345678"),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "INITIATED"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// lazy val answerConsentChallenge : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "consents" :: consentId :: "challenge" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentChallengeJsonV310 "
-// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentChallengeJsonV310]
-// }
-// consent <- Future(Consents.consentProvider.vend.checkAnswer(consentId, consentJson.answer)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getConsents,
-// implementedInApiVersion,
-// "getConsents",
-// "GET",
-// "/banks/BANK_ID/my/consents",
-// "Get Consents",
-// s"""
-// |This endpoint gets the Consents that the current User created.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val getConsents: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val url = cc.url
-// val limitParam = APIUtil.getHttpRequestUrlParam(url, "limit") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
-// case _ => 50
-// }
-// val offsetParam = APIUtil.getHttpRequestUrlParam(url, "offset") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
-// case _ => 0
-// }
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// rows <- Future {
-// DoobieConsentQueries.getConsentsByUserAndBank(
-// userId = user.userId,
-// bankId = bankId.value,
-// status = None,
-// limit = limitParam,
-// offset = offsetParam,
-// sortField = "created_date",
-// sortDirection = "desc"
-// )
-// }
-// } yield {
-// val consents = rows.map(r => ConsentJsonV310(r.consentId, r.jwt.getOrElse(""), r.status))
-// (ConsentsJsonV310(consents), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// revokeConsent,
-// implementedInApiVersion,
-// "revokeConsent",
-// "GET",
-// "/banks/BANK_ID/my/consents/CONSENT_ID/revoke",
-// "Revoke Consent",
-// s"""
-// |Revoke Consent for current user specified by CONSENT_ID
-// |
-// |There are a few reasons you might need to revoke an application’s access to a user’s account:
-// | - The user explicitly wishes to revoke the application’s access
-// | - You as the service provider have determined an application is compromised or malicious, and want to disable it
-// | - etc.
-// |
-// |Please note that this endpoint only supports the case:: "The user explicitly wishes to revoke the application’s access"
-// |
-// |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.
-// |The status of the token is changed to "REVOKED" so the next time the revoked client makes a request, their token will fail to validate.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// revokedConsentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val revokeConsent: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "consents" :: consentId :: "revoke" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, callContext, ConsentNotFound)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, cc=callContext) {
-// consent.mUserId == user.userId
-// }
-// consent <- Future(Consents.consentProvider.vend.revoke(consentId)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// createUserAuthContextUpdateRequest,
-// implementedInApiVersion,
-// nameOf(createUserAuthContextUpdateRequest),
-// "POST",
-// "/banks/BANK_ID/users/current/auth-context-updates/SCA_METHOD",
-// "Create User Auth Context Update Request",
-// s"""Create User Auth Context Update Request.
-// |${userAuthenticationMessage(true)}
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS" or "EMAIL". "EMAIL" is used for testing purposes.
-// |
-// |""",
-// postUserAuthContextJson,
-// userAuthContextUpdateJson,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// CreateUserAuthContextError,
-// UnknownError
-// ),
-// List(apiTagUser),
-// None
-// )
-//
-// lazy val createUserAuthContextUpdateRequest : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: scaMethod :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanCreateUserAuthContextUpdate, cc=callContext) {
-// checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(UserAuthContextUpdateRequestAllowedScaMethods, cc=callContext){
-// List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextJson]
-// }
-// (userAuthContextUpdate, callContext) <- NewStyle.function.validateUserAuthContextUpdateRequest(bankId.value, user.userId, postedData.key, postedData.value, scaMethod, callContext)
-// } yield {
-//
-// (JSONFactory310.createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// answerUserAuthContextUpdateChallenge,
-// implementedInApiVersion,
-// nameOf(answerUserAuthContextUpdateChallenge),
-// "POST",
-// "/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge",
-// "Answer Auth Context Update Challenge",
-// s"""
-// |Answer Auth Context Update Challenge.
-// |""",
-// PostUserAuthContextUpdateJsonV310(answer = "12345678"),
-// userAuthContextUpdateJson,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagUser :: Nil)
-//
-// lazy val answerUserAuthContextUpdateChallenge : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: authContextUpdateId :: "challenge" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextUpdateJsonV310 "
-// postUserAuthContextUpdateJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextUpdateJsonV310]
-// }
-// (userAuthContextUpdate, callContext) <- NewStyle.function.checkAnswer(authContextUpdateId, postUserAuthContextUpdateJson.answer, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userAuthContextUpdate.userId, callContext)
-// (_, callContext) <-
-// userAuthContextUpdate.status match {
-// case status if status == UserAuthContextUpdateStatus.ACCEPTED.toString =>
-// NewStyle.function.createUserAuthContext(
-// user,
-// userAuthContextUpdate.key,
-// userAuthContextUpdate.value,
-// callContext).map(x => (Some(x._1), x._2))
-// case _ =>
-// Future((None, callContext))
-// }
-// (_, callContext) <-
-// userAuthContextUpdate.key match {
-// case "CUSTOMER_NUMBER" =>
-// NewStyle.function.getOCreateUserCustomerLink(
-// bankId,
-// userAuthContextUpdate.value, // Customer number
-// user.userId,
-// callContext
-// )
-// case _ =>
-// Future((None, callContext))
-// }
-// } yield {
-// (createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getSystemView,
-// implementedInApiVersion,
-// "getSystemView",
-// "GET",
-// "/system-views/VIEW_ID",
-// "Get System View",
-// s"""Get System View
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// viewJSONV220,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canGetSystemView))
-// )
-//
-// lazy val getSystemView: OBPEndpoint = {
-// case "system-views" :: viewId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetSystemView, callContext)
-// view <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-// } yield {
-// (JSONFactory310.createViewJSON(view), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// createSystemView,
-// implementedInApiVersion,
-// nameOf(createSystemView),
-// "POST",
-// "/system-views",
-// "Create System View",
-// s"""Create a system view
-// |
-// | ${userAuthenticationMessage(true)} and the user needs to have access to the $canCreateSystemView entitlement.
-// | The 'alias' field in the JSON can take one of two values:
-// |
-// | * _public_: to use the public alias if there is one specified for the other account.
-// | * _private_: to use the private alias if there is one specified for the other account.
-// |
-// | * _''(empty string)_: to use no alias; the view shows the real name of the other account.
-// |
-// | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.
-// |
-// | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.
-// |
-// | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.
-// |
-// | Please note that system views cannot be public. In case you try to set it you will get the error $SystemViewCannotBePublicError
-// | """,
-// SwaggerDefinitionsJSON.createSystemViewJsonV300,
-// viewJsonV300,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canCreateSystemView))
-// )
-//
-// lazy val createSystemView : OBPEndpoint = {
-// //creates a system view
-// case "system-views" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canCreateSystemView, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CreateViewJson "
-// createViewJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CreateViewJsonV300]
-// }
-// //System views can not startwith '_'
-// _ <- Helper.booleanToFuture(failMsg = InvalidSystemViewFormat+s"Current view_name (${createViewJson.name})", cc = callContext) {
-// isValidSystemViewName(createViewJson.name)
-// }
-// _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=callContext) {
-// createViewJson.is_public == false
-// }
-// view <- ViewNewStyle.createSystemView(createViewJson.toCreateViewJson, callContext)
-// } yield {
-// (JSONFactory310.createViewJSON(view), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteSystemView,
-// implementedInApiVersion,
-// "deleteSystemView",
-// "DELETE",
-// "/system-views/VIEW_ID",
-// "Delete System View",
-// "Deletes the system view specified by VIEW_ID",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// BankAccountNotFound,
-// UnknownError,
-// "user does not have owner access"
-// ),
-// List(apiTagSystemView),
-// Some(List(canDeleteSystemView))
-// )
-//
-// lazy val deleteSystemView: OBPEndpoint = {
-// //deletes a view on an bank account
-// case "system-views" :: viewId :: Nil JsonDelete req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canDeleteSystemView, callContext)
-// _ <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-// view <- ViewNewStyle.deleteSystemView(ViewId(viewId), callContext)
-// } yield {
-// (Full(view), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateSystemView,
-// implementedInApiVersion,
-// nameOf(updateSystemView),
-// "PUT",
-// "/system-views/VIEW_ID",
-// "Update System View",
-// s"""Update an existing view on a bank account
-// |
-// |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.
-// |
-// |The json sent is the same as during view creation (above), with one difference: the 'name' field
-// |of a view is not editable (it is only set when a view is created)""",
-// updateSystemViewJson310,
-// viewJsonV300,
-// List(
-// InvalidJsonFormat,
-// AuthenticatedUserIsRequired,
-// BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canUpdateSystemView))
-// )
-//
-// lazy val updateSystemView : OBPEndpoint = {
-// //updates a view on a bank account
-// case "system-views" :: viewId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canUpdateSystemView, callContext)
-// updateJson <- Future { tryo{json.extract[UpdateViewJSON]} } map {
-// val msg = s"$InvalidJsonFormat The Json body should be the $UpdateViewJSON "
-// x => unboxFullOrFail(x, callContext, msg)
-// }
-// _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=callContext) {
-// updateJson.is_public == false
-// }
-// _ <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-// updatedView <- ViewNewStyle.updateSystemView(ViewId(viewId), updateJson, callContext)
-// } yield {
-// (JSONFactory310.createViewJSON(updatedView), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getOAuth2ServerJWKsURIs,
-// implementedInApiVersion,
-// "getOAuth2ServerJWKsURIs",
-// "GET",
-// "/jwks-uris",
-// "Get JSON Web Key (JWK) URIs",
-// """Get the OAuth2 server's public JSON Web Key (JWK) URIs.
-// | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects.
-// |
-// """.stripMargin,
-// EmptyBody,
-// oAuth2ServerJwksUrisJson,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi, apiTagOAuth, apiTagOIDC))
-//
-// lazy val getOAuth2ServerJWKsURIs: OBPEndpoint = {
-// case "jwks-uris" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// } yield {
-// (getOAuth2ServerJwksUrisJson(), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getMethodRoutings,
-// implementedInApiVersion,
-// nameOf(getMethodRoutings),
-// "GET",
-// "/management/method_routings",
-// "Get MethodRoutings",
-// s"""Get the all MethodRoutings.
-// |
-// |Query url parameters:
-// |
-// |* method_name: filter with method_name
-// |* active: if active = true, it will show all the webui_ props. Even if they are set yet, we will return all the default webui_ props
-// |
-// |eg:
-// |${getObpApiRoot}/v3.1.0/management/method_routings?active=true
-// |${getObpApiRoot}/v3.1.0/management/method_routings?method_name=getBank
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "method_routings",
-// (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("method-routing-id"))))
-// )
-// ,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMethodRouting, apiTagApi),
-// Some(List(canGetMethodRoutings))
-// )
-//
-//
-// lazy val getMethodRoutings: OBPEndpoint = {
-// case "management" :: "method_routings":: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetMethodRoutings, callContext)
-// methodRoutings <- NewStyle.function.getMethodRoutingsByMethodName(req.param("method_name"))
-// } yield {
-// val definedMethodRoutings = methodRoutings.sortWith(_.methodName < _.methodName)
-// val listCommons: List[MethodRoutingCommons] = req.param("active") match {
-// case Full("true") => (definedMethodRoutings ++ getDefaultMethodRountings ).sortWith(_.methodName < _.methodName)
-// case _ => definedMethodRoutings
-// }
-// (ListResult("method_routings", listCommons.map(_.toJson)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// /**
-// * get all default methodRountings,
-// * @return all default methodRounting#methodName, those just in mapped connector
-// */
-// private def getDefaultMethodRountings = {
-//
-// val methodRegex = """method \S+(? methodRegex.matcher(it.toString).matches())
-// .filter(_.asMethod.isPublic)
-// .map(_.asMethod)
-// .map(it => MethodRoutingCommons(
-// methodName = it.name.toString,
-// connectorName = "mapped",
-// isBankIdExactMatch = false,
-// bankIdPattern = Some("*"),
-// parameters= List.empty[MethodRoutingParam],
-// methodRoutingId = Some(""),
-// ))
-// .toList
-// }
-//
-// private val supportedConnectorNames = NewStyle.function.getSupportedConnectorNames().mkString("[", " | ", "]")
-// resourceDocs += ResourceDoc(
-// createMethodRouting,
-// implementedInApiVersion,
-// nameOf(createMethodRouting),
-// "POST",
-// "/management/method_routings",
-// "Create MethodRouting",
-// s"""Create a MethodRouting.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Explanation of Fields:
-// |
-// |* method_name is required String value, current supported value: $supportedConnectorNames
-// |* connector_name is required String value
-// |* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false
-// |* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex
-// |* parameters is optional array of key value pairs. You can set some parameters for this method
-// |
-// |note and CAVEAT!:
-// |
-// |* bank_id_pattern has to be empty for methods that do not take bank_id as a function parameter, otherwise might get empty result
-// |* methods that aggregate bank objects (e.g. getBankAccountsForUser) have to take any existing method routings for these objects into consideration
-// |* so if you create e.g. a bank specific method routing for getting an account, make sure that it is also served by endpoints getting ALL accounts for ALL banks
-// |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+"
-// |
-// |If the connector name starts with rest, parameters can contain "outBoundMapping" and "inBoundMapping", convert OutBound and InBound json structure.
-// |for example:
-// | outBoundMapping example, convert json from source to target:
-// |
-// |Build OutBound json value rules:
-// |1 set cId value with: outboundAdapterCallContext.correlationId value
-// |2 set bankId value with: concat bankId.value value with string helloworld
-// |3 set originalJson value with: whole source json, note: the field value expression is $$root
-// |
-// |
-// | inBoundMapping example, convert json from source to target:
-// |
-// |Build InBound json value rules:
-// |1 and 2 set inboundAdapterCallContext and status value: because field name ends with "$$default", remove "$$default" from field name, not change the value
-// |3 set fullName value with: concat string full: with result.name value
-// |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0].
-// |""",
-// MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))),
-// MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"),
-// List(MethodRoutingParam("url", "http://mydomain.com/xxx")),
-// Some("this-method-routing-Id")
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// InvalidConnectorName,
-// InvalidConnectorMethodName,
-// UnknownError
-// ),
-// List(apiTagMethodRouting, apiTagApi),
-// Some(List(canCreateMethodRouting)))
-//
-// lazy val createMethodRouting : OBPEndpoint = {
-// case "management" :: "method_routings" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateMethodRouting, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[MethodRoutingCommons]} "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// val entity = json.extract[MethodRoutingCommons]
-// entity.bankIdPattern match {
-// case Some(v) if(StringUtils.isBlank(v) || v.trim == "*") => entity.copy(bankIdPattern = Some(MethodRouting.bankIdPatternMatchAny))
-// case v => entity
-// }
-// }
-// _ <-NewStyle.function.tryons(InvalidOutBoundMapping, 400, callContext){
-// postedData.getOutBoundMapping
-// }
-// _ <-NewStyle.function.tryons(InvalidInBoundMapping, 400, callContext){
-// postedData.getInBoundMapping
-// }
-// connectorName = postedData.connectorName
-// methodName = postedData.methodName
-// _ <- Helper.booleanToFuture(s"$InvalidConnectorName please check connectorName: $connectorName or the connector($connectorName) is not supported for this sandbox. ", failCode=400, cc=callContext) {
-// NewStyle.function.getConnectorByName(connectorName).isDefined
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidConnectorMethodName please check methodName: $methodName", failCode=400, cc=callContext) {
-// //If connectorName = "internal", it mean the dynamic connector methods.
-// //all the connector method may not be existing yet. So need to get the method name from `mapped` first.
-// if(connectorName == "internal")
-// NewStyle.function.getConnectorMethod("mapped", methodName).isDefined
-// else
-// NewStyle.function.getConnectorMethod(connectorName, methodName).isDefined
-// }
-// invalidRegexMsg = s"$InvalidBankIdRegex The bankIdPattern is invalid regex, bankIdPatten: ${postedData.bankIdPattern.orNull} "
-// _ <- NewStyle.function.tryons(invalidRegexMsg, 400, callContext) {
-// // if do fuzzy match and bankIdPattern not empty, do check the regex is valid
-// if(!postedData.isBankIdExactMatch && postedData.bankIdPattern.isDefined) {
-// Pattern.compile(postedData.bankIdPattern.get)
-// }
-// }
-// _ <- NewStyle.function.checkMethodRoutingAlreadyExists(postedData, callContext)
-// Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(postedData)
-// } yield {
-// val commonsData: MethodRoutingCommons = methodRouting
-// (commonsData.toJson, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateMethodRouting,
-// implementedInApiVersion,
-// nameOf(updateMethodRouting),
-// "PUT",
-// "/management/method_routings/METHOD_ROUTING_ID",
-// "Update MethodRouting",
-// s"""Update a MethodRouting.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Explaination of Fields:
-// |
-// |* method_name is required String value, current supported value: $supportedConnectorNames
-// |* connector_name is required String value
-// |* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false
-// |* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex
-// |* parameters is optional array of key value pairs. You can set some paremeters for this method
-// |note:
-// |
-// |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+"
-// |
-// |If connector name start with rest, parameters can contain "outBoundMapping" and "inBoundMapping", to convert OutBound and InBound json structure.
-// |for example:
-// | outBoundMapping example, convert json from source to target:
-// |
-// |Build OutBound json value rules:
-// |1 set cId value with: outboundAdapterCallContext.correlationId value
-// |2 set bankId value with: concat bankId.value value with string helloworld
-// |3 set originalJson value with: whole source json, note: the field value expression is $$root
-// |
-// |
-// | inBoundMapping example, convert json from source to target:
-// |
-// |Build InBound json value rules:
-// |1 and 2 set inboundAdapterCallContext and status value: because field name ends with "$$default", remove "$$default" from field name, not change the value
-// |3 set fullName value with: concat string full: with result.name value
-// |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0].
-// |""",
-// MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))),
-// MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("this-method-routing-Id")),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// InvalidConnectorName,
-// InvalidConnectorMethodName,
-// UnknownError
-// ),
-// List(apiTagMethodRouting, apiTagApi),
-// Some(List(canUpdateMethodRouting)))
-//
-// lazy val updateMethodRouting : OBPEndpoint = {
-// case "management" :: "method_routings" :: methodRoutingId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateMethodRouting, callContext)
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[MethodRoutingCommons]} "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// val entity = json.extract[MethodRoutingCommons].copy(methodRoutingId = Some(methodRoutingId))
-// entity.bankIdPattern match {
-// case Some(v) if(StringUtils.isBlank(v) || v.trim == "*") => entity.copy(bankIdPattern = Some(MethodRouting.bankIdPatternMatchAny))
-// case v => entity
-// }
-// }
-// _ <-NewStyle.function.tryons(InvalidOutBoundMapping, 400, callContext){
-// putData.getOutBoundMapping
-// }
-// _ <-NewStyle.function.tryons(InvalidInBoundMapping, 400, callContext){
-// putData.getInBoundMapping
-// }
-// connectorName = putData.connectorName
-// methodName = putData.methodName
-// _ <- Helper.booleanToFuture(s"$InvalidConnectorName please check connectorName: $connectorName", failCode=400, cc=callContext) {
-// NewStyle.function.getConnectorByName(connectorName).isDefined
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidConnectorMethodName please check methodName: $methodName", failCode=400, cc=callContext) {
-// //If connectorName = "internal", it mean the dynamic connector methods.
-// //all the connector method may not be existing yet. So need to get the method name from `mapped` first.
-// if(connectorName == "internal")
-// NewStyle.function.getConnectorMethod("mapped", methodName).isDefined
-// else
-// NewStyle.function.getConnectorMethod(connectorName, methodName).isDefined
-// }
-// (_, _) <- NewStyle.function.getMethodRoutingById(methodRoutingId, callContext)
-//
-// invalidRegexMsg = s"$InvalidBankIdRegex The bankIdPattern is invalid regex, bankIdPatten: ${putData.bankIdPattern.orNull} "
-// _ <- NewStyle.function.tryons(invalidRegexMsg, 400, callContext) {
-// // if do fuzzy match and bankIdPattern not empty, do check the regex is valid
-// if(!putData.isBankIdExactMatch && putData.bankIdPattern.isDefined) {
-// Pattern.compile(putData.bankIdPattern.get)
-// }
-// }
-//
-// Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(putData)
-// } yield {
-// val commonsData: MethodRoutingCommons = methodRouting
-// (commonsData.toJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteMethodRouting,
-// implementedInApiVersion,
-// nameOf(deleteMethodRouting),
-// "DELETE",
-// "/management/method_routings/METHOD_ROUTING_ID",
-// "Delete MethodRouting",
-// s"""Delete a MethodRouting specified by METHOD_ROUTING_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMethodRouting, apiTagApi),
-// Some(List(canDeleteMethodRouting)))
-//
-// lazy val deleteMethodRouting : OBPEndpoint = {
-// case "management" :: "method_routings" :: methodRoutingId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getMethodRoutingById(methodRoutingId, callContext)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteMethodRouting, callContext)
-// deleted: Box[Boolean] <- NewStyle.function.deleteMethodRouting(methodRoutingId)
-// } yield {
-// (deleted, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerEmail,
-// implementedInApiVersion,
-// nameOf(updateCustomerEmail),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/email",
-// "Update the email of a Customer",
-// s"""Update an email of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerEmailJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerEmail :: Nil)
-// )
-//
-// lazy val updateCustomerEmail : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "email" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerEmail, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerEmailJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerEmailJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerScaData(
-// customerId,
-// None,
-// Some(putData.email),
-// None,
-// callContext)
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerNumber,
-// implementedInApiVersion,
-// nameOf(updateCustomerNumber),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/number",
-// "Update the number of a Customer",
-// s"""Update the number of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerNumberJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerNumber :: Nil)
-// )
-//
-// lazy val updateCustomerNumber : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "number" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerNumber, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerNumberJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerNumberJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-//
-// (customerNumberIsAvalible, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, putData.customer_number, callContext)
-// //There should not be a customer for this number, If there is, then we throw the exception.
-// _ <- Helper.booleanToFuture(failMsg= s"$CustomerNumberAlreadyExists Current customer_number(${putData.customer_number}) and Current bank_id(${bankId.value})", cc=callContext) {customerNumberIsAvalible}
-//
-// (customer, callContext) <- NewStyle.function.updateCustomerScaData(
-// customerId,
-// None,
-// None,
-// Some(putData.customer_number),
-// callContext)
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerMobileNumber,
-// implementedInApiVersion,
-// nameOf(updateCustomerMobileNumber),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/mobile-number",
-// "Update the mobile number of a Customer",
-// s"""Update the mobile number of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerMobileNumberJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerMobilePhoneNumber :: Nil)
-// )
-//
-// lazy val updateCustomerMobileNumber : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "mobile-number" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerMobilePhoneNumber, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerMobilePhoneNumberJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerMobilePhoneNumberJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerScaData(
-// customerId,
-// Some(putData.mobile_phone_number),
-// None,
-// None,
-// callContext)
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerIdentity,
-// implementedInApiVersion,
-// nameOf(updateCustomerIdentity),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/identity",
-// "Update the identity data of a Customer",
-// s"""Update the identity data of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerIdentityJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerIdentity :: Nil)
-// )
-// lazy val updateCustomerIdentity : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "identity" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerIdentity, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerIdentityJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerIdentityJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerGeneralData(
-// customerId,
-// Some(putData.legal_name),
-// None,
-// Some(putData.date_of_birth),
-// None,
-// None,
-// None,
-// None,
-// Some(putData.title),
-// None,
-// Some(putData.name_suffix),
-// None,
-// None,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerCreditLimit,
-// implementedInApiVersion,
-// nameOf(updateCustomerCreditLimit),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/credit-limit",
-// "Update the credit limit of a Customer",
-// s"""Update the credit limit of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerCreditLimitJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerCreditLimit :: Nil)
-// )
-//
-// lazy val updateCustomerCreditLimit : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "credit-limit" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerCreditLimit, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerCreditLimitJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerCreditLimitJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerCreditData(
-// customerId,
-// None,
-// None,
-// Some(putData.credit_limit),
-// callContext)
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerCreditRatingAndSource,
-// implementedInApiVersion,
-// nameOf(updateCustomerCreditRatingAndSource),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/credit-rating-and-source",
-// "Update the credit rating and source of a Customer",
-// s"""Update the credit rating and source of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerCreditRatingAndSourceJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerCreditRatingAndSource :: canUpdateCustomerCreditRatingAndSourceAtAnyBank :: Nil)
-// )
-//
-// lazy val updateCustomerCreditRatingAndSource : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "credit-rating-and-source" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, List(canUpdateCustomerCreditRatingAndSource,canUpdateCustomerCreditRatingAndSourceAtAnyBank), callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerCreditRatingAndSourceJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerCreditRatingAndSourceJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerCreditData(
-// customerId,
-// Some(putData.credit_rating),
-// Some(putData.credit_source),
-// None,
-// callContext)
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateAccount,
-// implementedInApiVersion,
-// nameOf(updateAccount),
-// "PUT",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID",
-// "Update Account",
-// s"""Update the account.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// updateAccountRequestJsonV310,
-// updateAccountResponseJsonV310,
-// List(InvalidJsonFormat, AuthenticatedUserIsRequired, UnknownError, BankAccountNotFound),
-// List(apiTagAccount),
-// Some(List(canUpdateAccount))
-// )
-//
-// lazy val updateAccount : OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateAccount, callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (bankAccount, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $UpdateAccountRequestJsonV310 "
-// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[UpdateAccountRequestJsonV310]
-// }
-// _ <- Helper.booleanToFuture(s"$UpdateBankAccountException Duplication detected in account routings, please specify only one value per routing scheme", cc=callContext){
-// consentJson.account_routings.map(_.scheme).distinct.size == consentJson.account_routings.size
-// }
-// alreadyExistAccountRoutings <- Future.sequence(consentJson.account_routings.map(accountRouting =>
-// NewStyle.function.getAccountRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext)
-// .map {
-// // If we find an already existing account routing linked to the account, it just mean we don't want to update it
-// case bankAccount if !(bankAccount._1.bankId == bankId && bankAccount._1.accountId == accountId) => Some(accountRouting)
-// case _ => None
-// } fallbackTo Future.successful(None)
-// ))
-// alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
-// case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
-// }
-// _ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", cc=callContext) {
-// alreadyExistingAccountRouting.isEmpty
-// }
-// (bankAccount,callContext) <- NewStyle.function.updateBankAccount(
-// bankId,
-// accountId,
-// consentJson.`type`,
-// consentJson.label,
-// consentJson.branch_id,
-// consentJson.account_routings.map(r => AccountRouting(r.scheme, r.address)),
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createUpdateResponseAccountJson(bankAccount), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// addCardForBank,
-// implementedInApiVersion,
-// nameOf(addCardForBank),
-// "POST",
-// "/management/banks/BANK_ID/cards",
-// "Create Card",
-// s"""Create Card at bank specified by BANK_ID .
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// createPhysicalCardJsonV310,
-// physicalCardJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// AllowedValuesAre,
-// UnknownError
-// ),
-// List(apiTagCard),
-// Some(List(canCreateCardsForBank)))
-// lazy val addCardForBank: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CreatePhysicalCardJsonV310 "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {json.extract[CreatePhysicalCardJsonV310]}
-//
-// _ <- postJson.allows match {
-// case List() => Future {true}
-// case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a)))
-// }
-//
-// failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ")
-// cardReplacementReason <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// postJson.replacement match {
-// case Some(value) => CardReplacementReason.valueOf(value.reason_requested)
-// case None => CardReplacementReason.valueOf(CardReplacementReason.FIRST.toString)
-// }
-// }
-//
-// _<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10)
-//
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canCreateCardsForBank, callContext)
-//
-// (_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext)
-//
-// (_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext)
-//
-// replacement = postJson.replacement match {
-// case Some(replacement) =>
-// Some(CardReplacementInfo(requestedDate = replacement.requested_date, cardReplacementReason))
-// case None => None
-// }
-// collected = postJson.collected match {
-// case Some(collected) => Some(CardCollectionInfo(collected))
-// case None => None
-// }
-// posted = postJson.posted match {
-// case Some(posted) => Option(CardPostedInfo(posted))
-// case None => None
-// }
-//
-// (card, callContext) <- NewStyle.function.createPhysicalCard(
-// bankCardNumber=postJson.card_number,
-// nameOnCard=postJson.name_on_card,
-// cardType = postJson.card_type,
-// issueNumber=postJson.issue_number,
-// serialNumber=postJson.serial_number,
-// validFrom=postJson.valid_from_date,
-// expires=postJson.expires_date,
-// enabled=postJson.enabled,
-// cancelled=false,
-// onHotList=false,
-// technology=postJson.technology,
-// networks= postJson.networks,
-// allows= postJson.allows,
-// accountId= postJson.account_id,
-// bankId=bankId.value,
-// replacement = replacement,
-// pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))),
-// collected = collected,
-// posted = posted,
-// customerId = postJson.customer_id,
-// cvv = "",//added from v500
-// brand = "",//added from v500
-// callContext
-// )
-// } yield {
-// (createPhysicalCardJson(card, u), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updatedCardForBank,
-// implementedInApiVersion,
-// nameOf(updatedCardForBank),
-// "PUT",
-// "/management/banks/BANK_ID/cards/CARD_ID",
-// "Update Card",
-// s"""Update Card at bank specified by CARD_ID .
-// |${userAuthenticationMessage(true)}
-// |""",
-// updatePhysicalCardJsonV310,
-// physicalCardJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// AllowedValuesAre,
-// UnknownError
-// ),
-// List(apiTagCard),
-// Some(List(canUpdateCardsForBank)))
-// lazy val updatedCardForBank: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateCardsForBank, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $UpdatePhysicalCardJsonV310 "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[UpdatePhysicalCardJsonV310]
-// }
-//
-// _ <- postJson.allows match {
-// case List() => Future {1}
-// case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a)))
-// }
-//
-// failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ")
-// _ <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// CardReplacementReason.valueOf(postJson.replacement.reason_requested)
-// }
-//
-// _<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10)
-//
-// (_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext)
-//
-// (card, callContext) <- NewStyle.function.getPhysicalCardForBank(bankId, cardId, callContext)
-//
-// (_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext)
-//
-// (card, callContext) <- NewStyle.function.updatePhysicalCard(
-// cardId = cardId,
-// bankCardNumber=card.bankCardNumber,
-// cardType = postJson.card_type,
-// nameOnCard=postJson.name_on_card,
-// issueNumber=postJson.issue_number,
-// serialNumber=postJson.serial_number,
-// validFrom=postJson.valid_from_date,
-// expires=postJson.expires_date,
-// enabled=postJson.enabled,
-// cancelled=false,
-// onHotList=false,
-// technology=postJson.technology,
-// networks= postJson.networks,
-// allows= postJson.allows,
-// accountId= postJson.account_id,
-// bankId=bankId.value,
-// replacement= Some(CardReplacementInfo(requestedDate = postJson.replacement.requested_date, CardReplacementReason.valueOf(postJson.replacement.reason_requested))),
-// pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))),
-// collected= Option(CardCollectionInfo(postJson.collected)),
-// posted = Option(CardPostedInfo(postJson.posted)),
-// customerId = postJson.customer_id,
-// callContext = callContext
-// )
-// } yield {
-// (createPhysicalCardJson(card, u), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getCardsForBank,
-// implementedInApiVersion,
-// nameOf(getCardsForBank),
-// "GET",
-// "/management/banks/BANK_ID/cards",
-// "Get Cards for the specified bank",
-// s"""Should be able to filter on the following fields
-// |
-// |eg:/management/banks/BANK_ID/cards?customer_id=66214b8e-259e-44ad-8868-3eb47be70646&account_id=8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0
-// |
-// |1 customer_id should be valid customer_id, otherwise, it will return an empty card list.
-// |
-// |2 account_id should be valid account_id , otherwise, it will return an empty card list.
-// |
-// |
-// |${userAuthenticationMessage(true)}""".stripMargin,
-// EmptyBody,
-// physicalCardsJsonV310,
-// List(AuthenticatedUserIsRequired,BankNotFound, UnknownError),
-// List(apiTagCard))
-// lazy val getCardsForBank : OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetCardsForBank, callContext)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (cards,callContext) <- NewStyle.function.getPhysicalCardsForBank(bank, u, obpQueryParams, callContext)
-// } yield {
-// (createPhysicalCardsJson(cards, u), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getCardForBank,
-// implementedInApiVersion,
-// nameOf(getCardForBank),
-// "GET",
-// "/management/banks/BANK_ID/cards/CARD_ID",
-// "Get Card By Id",
-// s"""
-// |This will the datails of the card.
-// |It shows the account infomation which linked the the card.
-// |Also shows the card attributes of the card.
-// |
-// """.stripMargin,
-// EmptyBody,
-// physicalCardWithAttributesJsonV310,
-// List(AuthenticatedUserIsRequired,BankNotFound, UnknownError),
-// List(apiTagCard),
-// Some(List(canGetCardsForBank)))
-// lazy val getCardForBank : OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetCardsForBank, callContext)
-// (_, callContext)<- NewStyle.function.getBank(bankId, callContext)
-// (card, callContext) <- NewStyle.function.getPhysicalCardForBank(bankId, cardId, callContext)
-// (cardAttributes, callContext) <- NewStyle.function.getCardAttributesFromProvider(cardId, callContext)
-// } yield {
-// val views: List[View] = Views.views.vend.assignedViewsForAccount(BankIdAccountId(card.account.bankId, card.account.accountId))
-// val commonsData: List[CardAttributeCommons]= cardAttributes
-// (createPhysicalCardWithAttributesJson(card, commonsData, u, views), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteCardForBank,
-// implementedInApiVersion,
-// nameOf(deleteCardForBank),
-// "DELETE",
-// "/management/banks/BANK_ID/cards/CARD_ID",
-// "Delete Card",
-// s"""Delete a Card at bank specified by CARD_ID .
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// AllowedValuesAre,
-// UnknownError
-// ),
-// List(apiTagCard),
-// Some(List(canCreateCardsForBank)))
-// lazy val deleteCardForBank: OBPEndpoint = {
-// case "management"::"banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canDeleteCardsForBank, callContext)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, Some(cc))
-// (result, callContext) <- NewStyle.function.deletePhysicalCardForBank(bankId, cardId, callContext)
-// } yield {
-// (Full(result), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createCardAttribute,
-// implementedInApiVersion,
-// nameOf(createCardAttribute),
-// "POST",
-// "/management/banks/BANK_ID/cards/CARD_ID/attribute",
-// "Create Card Attribute",
-// s""" Create Card Attribute
-// |
-// |Card Attributes are used to describe a financial Product with a list of typed key value pairs.
-// |
-// |Each Card Attribute is linked to its Card by CARD_ID
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// CardAttributeJson(
-// cardAttributeNameExample.value,
-// CardAttributeType.DOUBLE.toString,
-// cardAttributeValueExample.value
-// ),
-// CardAttributeCommons(
-// Some(BankId(bankIdExample.value)),
-// Some(cardIdExample.value),
-// Some(cardAttributeIdExample.value),
-// cardAttributeNameExample.value,
-// CardAttributeType.DOUBLE,
-// cardAttributeValueExample.value),
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCard, apiTagCardAttribute, apiTagAttribute))
-//
-// lazy val createCardAttribute : OBPEndpoint = {
-// case "management"::"banks" :: bankId :: "cards" :: cardId :: "attribute" :: Nil JsonPost json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// (_, callContext) <- NewStyle.function.getPhysicalCardForBank(BankId(bankId), cardId, callContext)
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CardAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CardAttributeJson]
-// }
-//
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CardAttributeType.DOUBLE}(12.1234), ${CardAttributeType.STRING}(TAX_NUMBER), ${CardAttributeType.INTEGER}(123) and ${CardAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// createCardAttribute <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// CardAttributeType.withName(postedData.`type`)
-// }
-//
-// (cardAttribute, callContext) <- NewStyle.function.createOrUpdateCardAttribute(
-// Some(BankId(bankId)),
-// Some(cardId),
-// None,
-// postedData.name,
-// createCardAttribute,
-// postedData.value,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// val commonsData: CardAttributeCommons = cardAttribute
-// (commonsData, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// updateCardAttribute,
-// implementedInApiVersion,
-// nameOf(updateCardAttribute),
-// "PUT",
-// "/management/banks/BANK_ID/cards/CARD_ID/attributes/CARD_ATTRIBUTE_ID",
-// "Update Card Attribute",
-// s""" Update Card Attribute
-// |
-// |Card Attributes are used to describe a financial Product with a list of typed key value pairs.
-// |
-// |Each Card Attribute is linked to its Card by CARD_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// CardAttributeJson(
-// cardAttributeNameExample.value,
-// CardAttributeType.DOUBLE.toString,
-// cardAttributeValueExample.value
-// ),
-// CardAttributeCommons(
-// Some(BankId(bankIdExample.value)),
-// Some(cardIdExample.value),
-// Some(cardAttributeIdExample.value),
-// cardAttributeNameExample.value,
-// CardAttributeType.DOUBLE,
-// cardAttributeValueExample.value),
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCard, apiTagCardAttribute, apiTagAttribute))
-//
-// lazy val updateCardAttribute : OBPEndpoint = {
-// case "management"::"banks" :: bankId :: "cards" :: cardId :: "attributes" :: cardAttributeId :: Nil JsonPut json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext)
-// (_, callContext) <- NewStyle.function.getPhysicalCardForBank(BankId(bankId), cardId, callContext)
-// (_, callContext) <- NewStyle.function.getCardAttributeById(cardAttributeId, callContext)
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CardAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CardAttributeJson]
-// }
-//
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CardAttributeType.DOUBLE}(12.1234), ${CardAttributeType.STRING}(TAX_NUMBER), ${CardAttributeType.INTEGER}(123) and ${CardAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// createCardAttribute <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// CardAttributeType.withName(postedData.`type`)
-// }
-//
-// (cardAttribute, callContext) <- NewStyle.function.createOrUpdateCardAttribute(
-// Some(BankId(bankId)),
-// Some(cardId),
-// Some(cardAttributeId),
-// postedData.name,
-// createCardAttribute,
-// postedData.value,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// val commonsData: CardAttributeCommons = cardAttribute
-// (commonsData, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerBranch,
-// implementedInApiVersion,
-// nameOf(updateCustomerBranch),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/branch",
-// "Update the Branch of a Customer",
-// s"""Update the Branch of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putCustomerBranchJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerIdentity :: Nil)
-// )
-// lazy val updateCustomerBranch : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "branch" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerBranch, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerBranchJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerBranchJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerGeneralData(
-// customerId,
-// None,
-// None,
-// None,
-// None,
-// None,
-// None,
-// None,
-// None,
-// Some(putData.branch_id),
-// None,
-// None,
-// None,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomerData,
-// implementedInApiVersion,
-// nameOf(updateCustomerData),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/data",
-// "Update the other data of a Customer",
-// s"""Update the other data of the Customer specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// putUpdateCustomerDataJsonV310,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(canUpdateCustomerIdentity :: Nil)
-// )
-// lazy val updateCustomerData : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "data" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerData, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerDataJsonV310 "
-// putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutUpdateCustomerDataJsonV310]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customer, callContext) <- NewStyle.function.updateCustomerGeneralData(
-// customerId,
-// None,
-// Some(CustomerFaceImage(putData.face_image.date, putData.face_image.url)),
-// None,
-// Some(putData.relationship_status),
-// Some(putData.dependants),
-// Some(putData.highest_education_attained),
-// Some(putData.employment_status),
-// None,
-// None,
-// None,
-// None,
-// None,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// createAccount,
-// implementedInApiVersion,
-// "createAccount",
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID",
-// "Create Account",
-// """Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.
-// |
-// |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.
-// |
-// |If the PUT body USER_ID *is* specified, the logged in user must have the Role canCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.
-// |
-// |If the PUT body USER_ID is *not* specified, the account will be owned by the logged in User.
-// |
-// |The 'product_code' field SHOULD be a product_code from Product.
-// |If the 'product_code' matches a product_code from Product, account attributes will be created that match the Product Attributes.
-// |
-// |Note: The Amount MUST be zero.""".stripMargin,
-// createAccountRequestJsonV310,
-// createAccountResponseJsonV310,
-// List(
-// InvalidJsonFormat,
-// BankNotFound,
-// AuthenticatedUserIsRequired,
-// InvalidUserId,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// UserNotFoundById,
-// UserHasMissingRoles,
-// InvalidAccountBalanceAmount,
-// InvalidAccountInitialBalance,
-// InitialBalanceMustBeZero,
-// InvalidAccountBalanceCurrency,
-// AccountIdAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagAccount,apiTagOnboarding),
-// Some(List(canCreateAccount))
-// )
-//
-//
-// lazy val createAccount : OBPEndpoint = {
-// // Create a new account
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: Nil JsonPut json -> _ => {
-// cc =>{
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (account, callContext) <- Connector.connector.vend.checkBankAccountExists(bankId, accountId, callContext)
-// _ <- Helper.booleanToFuture(AccountIdAlreadyExists, cc=callContext){
-// account.isEmpty
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} "
-// createAccountJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CreateAccountRequestJsonV310]
-// }
-// loggedInUserId = u.userId
-// userIdAccountOwner = if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id else loggedInUserId
-// _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// (postedOrLoggedInUser,callContext) <- NewStyle.function.findByUserId(userIdAccountOwner, callContext)
-// // User can create account for self or an account for another user if they have CanCreateAccount role
-// _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// _ <- if (userIdAccountOwner == loggedInUserId) Future.successful(Full(Unit))
-// else NewStyle.function.hasEntitlement(bankId.value, loggedInUserId, canCreateAccount, callContext, s"${UserHasMissingRoles} $canCreateAccount or create account for self")
-//
-// initialBalanceAsString = createAccountJson.balance.amount
-// accountType = createAccountJson.product_code
-// accountLabel = createAccountJson.label
-// initialBalanceAsNumber <- NewStyle.function.tryons(InvalidAccountInitialBalance, 400, callContext) {
-// BigDecimal(initialBalanceAsString)
-// }
-// _ <- Helper.booleanToFuture(InitialBalanceMustBeZero, cc=callContext){0 == initialBalanceAsNumber}
-// _ <- Helper.booleanToFuture(InvalidISOCurrencyCode, cc=callContext){isValidCurrencyISOCode(createAccountJson.balance.currency)}
-// currency = createAccountJson.balance.currency
-// (_, callContext ) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", 400, cc=callContext){
-// createAccountJson.account_routings.map(_.scheme).distinct.size == createAccountJson.account_routings.size
-// }
-// alreadyExistAccountRoutings <- Future.sequence(createAccountJson.account_routings.map(accountRouting =>
-// NewStyle.function.getAccountRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
-// ))
-// alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
-// case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
-// }
-// _ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", cc=callContext) {
-// alreadyExistingAccountRouting.isEmpty
-// }
-// (bankAccount,callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// accountId,
-// accountType,
-// accountLabel,
-// currency,
-// initialBalanceAsNumber,
-// postedOrLoggedInUser.name,
-// createAccountJson.branch_id,
-// createAccountJson.account_routings.map(r => AccountRouting(r.scheme, r.address)),
-// callContext
-// )
-// (productAttributes, callContext) <- NewStyle.function.getProductAttributesByBankAndCode(bankId, ProductCode(accountType), callContext)
-// (accountAttributes, callContext) <- NewStyle.function.createAccountAttributes(
-// bankId,
-// accountId,
-// ProductCode(accountType),
-// productAttributes,
-// None,
-// callContext: Option[CallContext]
-// )
-// //1 Create or Update the `Owner` for the new account
-// //2 Add permission to the user
-// //3 Set the user as the account holder
-// _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(bankId, accountId, postedOrLoggedInUser, callContext)
-// } yield {
-// (JSONFactory310.createAccountJSON(userIdAccountOwner, bankAccount, accountAttributes), HttpCode.`201`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getPrivateAccountByIdFull,
-// implementedInApiVersion,
-// nameOf(getPrivateAccountByIdFull),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account",
-// "Get Account by Id (Full)",
-// """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):
-// |
-// |* Number
-// |* Owners
-// |* Type
-// |* Balance
-// |* IBAN
-// |* Available views (sorted by short_name)
-// |
-// |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).
-// |
-// |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.
-// |This call provides balance and other account information via delegated authentication using OAuth.
-// |
-// |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.
-// |""".stripMargin,
-// EmptyBody,
-// moderatedAccountJSON310,
-// List(BankNotFound,AccountNotFound,ViewNotFound, UserNoPermissionAccessView, UnknownError),
-// apiTagAccount :: Nil)
-// lazy val getPrivateAccountByIdFull : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "account" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext)
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(account, view, Full(u), callContext)
-// (accountAttributes, callContext) <- NewStyle.function.getAccountAttributesByAccount(
-// bankId,
-// accountId,
-// callContext: Option[CallContext])
-// } yield {
-// val availableViews = Views.views.vend.privateViewsUserCanAccessForAccount(u, BankIdAccountId(account.bankId, account.accountId))
-// val viewsAvailable = availableViews.map(JSONFactory.createViewJSON).sortBy(_.short_name)
-// (JSONFactory310.createBankAccountJSON(moderatedAccount, viewsAvailable, accountAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// saveHistoricalTransaction,
-// implementedInApiVersion,
-// nameOf(saveHistoricalTransaction),
-// "POST",
-// "/management/historical/transactions ",
-// "Save Historical Transactions ",
-// s"""
-// |Import the historical transactions.
-// |
-// |The fields bank_id, account_id, counterparty_id in the json body are all optional ones.
-// |It support transfer money from account to account, account to counterparty and counterparty to counterparty
-// |Both bank_id + account_id and counterparty_id can identify the account, so OBP only need one of them to make the payment.
-// |So:
-// |When you need the account to account, just omit counterparty_id field.eg:
-// |{
-// | "from": {
-// | "bank_id": "gh.29.uk",
-// | "account_id": "1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// | },
-// | "to": {
-// | "bank_id": "gh.29.uk",
-// | "account_id": "2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// | },
-// | "value": {
-// | "currency": "GBP",
-// | "amount": "10"
-// | },
-// | "description": "this is for work",
-// | "posted": "2017-09-19T02:31:05Z",
-// | "completed": "2017-09-19T02:31:05Z",
-// | "type": "SANDBOX_TAN",
-// | "charge_policy": "SHARED"
-// |}
-// |
-// |When you need the counterparty to counterparty, need to omit bank_id and account_id field.eg:
-// |{
-// | "from": {
-// | "counterparty_id": "f6392b7d-4218-45ea-b9a7-eaa71c0202f9"
-// | },
-// | "to": {
-// | "counterparty_id": "26392b7d-4218-45ea-b9a7-eaa71c0202f9"
-// | },
-// | "value": {
-// | "currency": "GBP",
-// | "amount": "10"
-// | },
-// | "description": "this is for work",
-// | "posted": "2017-09-19T02:31:05Z",
-// | "completed": "2017-09-19T02:31:05Z",
-// | "type": "SANDBOX_TAN",
-// | "charge_policy": "SHARED"
-// |}
-// |
-// |or, you can counterparty to account
-// |{
-// | "from": {
-// | "counterparty_id": "f6392b7d-4218-45ea-b9a7-eaa71c0202f9"
-// | },
-// | "to": {
-// | "bank_id": "gh.29.uk",
-// | "account_id": "8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// | },
-// | "value": {
-// | "currency": "GBP",
-// | "amount": "10"
-// | },
-// | "description": "this is for work",
-// | "posted": "2017-09-19T02:31:05Z",
-// | "completed": "2017-09-19T02:31:05Z",
-// | "type": "SANDBOX_TAN",
-// | "charge_policy": "SHARED"
-// |}
-// |
-// |This call is experimental.
-// """.stripMargin,
-// postHistoricalTransactionJson,
-// postHistoricalTransactionResponseJson,
-// List(
-// InvalidJsonFormat,
-// BankNotFound,
-// AccountNotFound,
-// CounterpartyNotFoundByCounterpartyId,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest),
-// Some(List(canCreateHistoricalTransaction))
-// )
-//
-//
-// lazy val saveHistoricalTransaction : OBPEndpoint = {
-// case "management" :: "historical" :: "transactions" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canCreateHistoricalTransaction, callContext)
-//
-// // Check the input JSON format, here is just check the common parts of all four types
-// transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostHistoricalTransactionJson ", 400, callContext) {
-// json.extract[PostHistoricalTransactionJson]
-// }
-// fromAccountPost = transDetailsJson.from
-// (fromAccount, callContext) <- if (fromAccountPost.bank_id.isDefined && fromAccountPost.account_id.isDefined && fromAccountPost.counterparty_id.isEmpty){
-// for{
-// (_, callContext) <- NewStyle.function.getBank(BankId(fromAccountPost.bank_id.get), callContext)
-// (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(BankId(fromAccountPost.bank_id.get), AccountId(fromAccountPost.account_id.get), callContext)
-// } yield {
-// (fromAccount, callContext)
-// }
-// } else if (fromAccountPost.bank_id.isEmpty && fromAccountPost.account_id.isEmpty && fromAccountPost.counterparty_id.isDefined){
-// for {
-// (fromCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(fromAccountPost.counterparty_id.get), cc.callContext)
-// (fromAccount, callContext) <- NewStyle.function.getBankAccountFromCounterparty(fromCounterparty, false, callContext)
-// }yield{
-// (fromAccount, callContext)
-// }
-// } else {
-// throw new RuntimeException(s"$InvalidJsonFormat from object should only contain bank_id and account_id or counterparty_id in the post json body.")
-// }
-//
-//
-// toAccountPost = transDetailsJson.to
-// (toAccount, callContext) <- if (toAccountPost.bank_id.isDefined && toAccountPost.account_id.isDefined && toAccountPost.counterparty_id.isEmpty){
-// for{
-// (_, callContext) <- NewStyle.function.getBank(BankId(toAccountPost.bank_id.get), callContext)
-// (toAccount, callContext) <- NewStyle.function.checkBankAccountExists(BankId(toAccountPost.bank_id.get), AccountId(toAccountPost.account_id.get), callContext)
-// } yield {
-// (toAccount, callContext)
-// }
-// } else if (toAccountPost.bank_id.isEmpty && toAccountPost.account_id.isEmpty && toAccountPost.counterparty_id.isDefined){
-// for {
-// (toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toAccountPost.counterparty_id.get), cc.callContext)
-// (toAccount, callContext) <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
-// }yield{
-// (toAccount, callContext)
-// }
-// } else {
-// throw new RuntimeException(s"$InvalidJsonFormat to object should only contain bank_id and account_id or counterparty_id in the post json body.")
-// }
-//
-// amountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", 400, callContext) {
-// BigDecimal(transDetailsJson.value.amount)
-// }
-//
-// _ <- Helper.booleanToFuture(s"${NotPositiveAmount} Current input is: '${amountNumber}'", cc=callContext) {
-// amountNumber > BigDecimal("0")
-// }
-//
-// posted <- NewStyle.function.tryons(s"$InvalidDateFormat Current `posted` field is ${transDetailsJson.posted}. Please use this format ${DateWithSecondsFormat.toPattern}! ", 400, callContext) {
-// new SimpleDateFormat(DateWithSeconds).parse(transDetailsJson.posted)
-// }
-//
-// completed <- NewStyle.function.tryons(s"$InvalidDateFormat Current `completed` field is ${transDetailsJson.completed}. Please use this format ${DateWithSecondsFormat.toPattern}! ", 400, callContext) {
-// new SimpleDateFormat(DateWithSeconds).parse(transDetailsJson.completed)
-// }
-//
-// // Prevent default value for transaction request type (at least).
-// _ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
-// isValidCurrencyISOCode(transDetailsJson.value.currency)
-// }
-//
-// amountOfMoneyJson = AmountOfMoneyJsonV121(transDetailsJson.value.currency, transDetailsJson.value.amount)
-// chargePolicy = transDetailsJson.charge_policy
-//
-// //There is no constraint for the type at the moment
-// transactionType = transDetailsJson.`type`
-//
-// (transactionId, callContext) <- NewStyle.function.makeHistoricalPayment(
-// fromAccount,
-// toAccount,
-// posted,
-// completed,
-// amountNumber,
-// transDetailsJson.value.currency,
-// transDetailsJson.description,
-// transactionType,
-// chargePolicy,
-// callContext
-// )
-// } yield {
-// (JSONFactory310.createPostHistoricalTransactionResponseJson(
-// transactionId,
-// fromAccountPost,
-// toAccountPost,
-// value= amountOfMoneyJson,
-// description = transDetailsJson.description,
-// posted,
-// completed,
-// transactionRequestType = transactionType,
-// chargePolicy =transDetailsJson.charge_policy), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getWebUiProps,
-// implementedInApiVersion,
-// nameOf(getWebUiProps),
-// "GET",
-// "/management/webui_props",
-// "Get WebUiProps",
-// s"""
-// |
-// |Get WebUiProps - properties that configure the Web UI behavior and appearance.
-// |
-// |Properties with names starting with "webui_" can be stored in the database and managed via API.
-// |
-// |**Data Sources:**
-// |
-// |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.
-// |
-// |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.
-// |
-// |**Query Parameter:**
-// |
-// |* `active` (optional, boolean string, default: "false")
-// | - If `active=false` or omitted: Returns only explicit props from the database
-// | - If `active=true`: Returns explicit props + implicit (default) props from configuration file
-// | - When both sources have the same property name, the database value takes precedence
-// | - Implicit props are marked with `webUiPropsId = "default"`
-// |
-// |**Examples:**
-// |
-// |Get only database-stored props:
-// |${getObpApiRoot}/v3.1.0/management/webui_props
-// |
-// |Get database props combined with defaults:
-// |${getObpApiRoot}/v3.1.0/management/webui_props?active=true
-// |
-// |For more details about WebUI Props, including how to set config file defaults and precedence order, see ${Glossary.getGlossaryItemLink("webui_props")}.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "webui_props",
-// (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"))))
-// )
-// ,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagWebUiProps),
-// Some(List(canGetWebUiProps))
-// )
-//
-//
-// lazy val getWebUiProps: OBPEndpoint = {
-// case "management" :: "webui_props":: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val active = ObpS.param("active").getOrElse("false")
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// invalidMsg = s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """
-// isActived <- NewStyle.function.tryons(invalidMsg, 400, callContext) {
-// active.toBoolean
-// }
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetWebUiProps, callContext)
-// explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() }
-// implicitWebUiPropsRemovedDuplicated = if(isActived){
-// val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId= Some("default")))
-// if(explicitWebUiProps.nonEmpty){
-// //get the same name props in the `implicitWebUiProps`
-// val duplicatedProps : List[WebUiPropsCommons]= explicitWebUiProps.map(explicitWebUiProp => implicitWebUiProps.filter(_.name == explicitWebUiProp.name)).flatten
-// //remove the depulicated fields from `implicitWebUiProps`
-// implicitWebUiProps diff duplicatedProps
-// }
-// else implicitWebUiProps.distinct
-// } else {
-// List.empty[WebUiPropsCommons]
-// }
-// } yield {
-// val listCommons: List[WebUiPropsCommons] = explicitWebUiProps ++ implicitWebUiPropsRemovedDuplicated
-// (ListResult("webui_props", listCommons), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createWebUiProps,
-// implementedInApiVersion,
-// nameOf(createWebUiProps),
-// "POST",
-// "/management/webui_props",
-// "Create WebUiProps",
-// s"""Create a WebUiProps.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Explaination of Fields:
-// |
-// |* name is required String value
-// |* value is required String value
-// |
-// |The line break and double quotations should do escape, example:
-// |
-// |```
-// |
-// |{"name": "webui_some", "value": "this value
-// |have "line break" and double quotations."}
-// |
-// |```
-// |should do escape like this:
-// |
-// |```
-// |
-// |{"name": "webui_some", "value": "this value\\nhave \\"line break\\" and double quotations."}
-// |
-// |```
-// |
-// |Insert image examples:
-// |
-// |```
-// |// set width=100 and height=50
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |// only set height=50
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |// only width=20%
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |```
-// |
-// |""",
-// WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com"),
-// WebUiPropsCommons( "webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("some-web-ui-props-id")),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagWebUiProps),
-// Some(List(canCreateWebUiProps)))
-//
-// lazy val createWebUiProps : OBPEndpoint = {
-// case "management" :: "webui_props" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateWebUiProps, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[WebUiPropsCommons]} "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[WebUiPropsCommons]
-// }
-// invalidMsg = s"""$InvalidWebUiProps name must be start with webui_, but current post name is: ${postedData.name} """
-// _ <- NewStyle.function.tryons(invalidMsg, 400, callContext) {
-// require(postedData.name.startsWith("webui_"))
-// }
-// Full(webUiProps) <- Future { MappedWebUiPropsProvider.createOrUpdate(postedData) }
-// } yield {
-// val commonsData: WebUiPropsCommons = webUiProps
-// (commonsData, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteWebUiProps,
-// implementedInApiVersion,
-// nameOf(deleteWebUiProps),
-// "DELETE",
-// "/management/webui_props/WEB_UI_PROPS_ID",
-// "Delete WebUiProps",
-// s"""Delete a WebUiProps specified by WEB_UI_PROPS_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagWebUiProps),
-// Some(List(canDeleteWebUiProps)))
-//
-// lazy val deleteWebUiProps : OBPEndpoint = {
-// case "management" :: "webui_props" :: webUiPropsId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteWebUiProps, callContext)
-// deleted <- Future { MappedWebUiPropsProvider.delete(webUiPropsId) } map {
-// unboxFullOrFail(_, callContext)
-// }
-// } yield {
-// (deleted, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getBankAccountsBalances,
-// implementedInApiVersion,
-// nameOf(getBankAccountsBalances),
-// "GET",
-// "/banks/BANK_ID/balances",
-// "Get Accounts Balances",
-// """Get the Balances for the Accounts of the current User at one bank.""",
-// EmptyBody,
-// accountBalancesV310Json,
-// List(UnknownError),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountsBalances : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u, bankId)
-// (accountsBalances, callContext)<- BalanceNewStyle.getBankAccountsBalances(availablePrivateAccounts, callContext)
-// } yield{
-// (createBalancesJson(accountsBalances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// enableDisableConsumers,
-// implementedInApiVersion,
-// "enableDisableConsumers",
-// "PUT",
-// "/management/consumers/CONSUMER_ID",
-// "Enable or Disable Consumers",
-// s"""Enable/Disable a Consumer specified by CONSUMER_ID.
-// |
-// |""",
-// putEnabledJSON,
-// putEnabledJSON,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canEnableConsumers,canDisableConsumers)))
-//
-//
-// lazy val enableDisableConsumers: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putData <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
-// json.extract[PutEnabledJSON]
-// }
-// _ <- putData.enabled match {
-// case true => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canEnableConsumers, callContext)
-// case false => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canDisableConsumers, callContext)
-// }
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// updatedConsumer <- Future {
-// Consumers.consumers.vend.updateConsumer(consumer.id.get, None, None, Some(putData.enabled), None, None, None, None, None,None, None, None) ?~! "Cannot update Consumer"
-// }
-// } yield {
-// // Format the data as json
-// val json = PutEnabledJSON(updatedConsumer.map(_.isActive.get).getOrElse(false))
-// // Return
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// }
-//}
-//
-//object APIMethods310 {
-// lazy val newStyleEndpoints: List[(String, String)] = Implementations3_1_0.resourceDocs.map {
-// rd => (rd.partialFunctionName, rd.implementedInApiVersion.toString())
-// }.toList
-//}
diff --git a/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala b/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala
deleted file mode 100644
index d9725aa854..0000000000
--- a/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
-Open Bank Project - API
-Copyright (C) 2011-2019, TESOBE GmbH.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
-Email: contact@tesobe.com
-TESOBE GmbH.
-Osloer Strasse 16/17
-Berlin 13359, Germany
-
-This product includes software developed at
-TESOBE (http://www.tesobe.com/)
-
- */
-package code.api.v3_1_0
-
-import scala.language.reflectiveCalls
-import code.api.OBPRestHelper
-import code.api.util.VersionedOBPApis
-import code.api.v1_2_1.Http4s121
-import code.api.v2_2_0.Http4s220
-import code.api.v3_0_0.OBPAPI3_0_0
-import code.util.Helper.MdcLoggable
-import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
-
-/*
-This file defines which endpoints from all the versions are available in v3.1.0.
-All v3.1.0 endpoints have been migrated to Http4s310 — this object is retained
-only for resource-doc aggregation and the Lift dispatch registry.
- */
-object OBPAPI3_1_0 extends OBPRestHelper with MdcLoggable with VersionedOBPApis {
-
- val version: ApiVersion = ApiVersion.v3_1_0
- lazy val versionStatus = ApiVersionStatus.STABLE.toString
-
- // Re-exports so callers that still import OBPAPI3_1_0.ImplementationsX keep compiling.
- val Implementations3_1_0 = Http4s310.Implementations3_1_0
- val Implementations1_2_1 = Http4s121.Implementations1_2_1
- val Implementations2_2_0 = Http4s220.Implementations2_2_0
-
- def allResourceDocs = collectResourceDocs(
- OBPAPI3_0_0.allResourceDocs,
- Http4s310.resourceDocs
- )
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
- // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here.
-}
diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
deleted file mode 100644
index 97bf38fe57..0000000000
--- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
+++ /dev/null
@@ -1,17056 +0,0 @@
-package code.api.v4_0_0
-
-/**
- * All v4.0.0 Lift endpoints have been migrated to Http4s400.
- * This stub is kept so that existing test files that import
- * APIMethods400.Implementations4_0_0 continue to compile.
- */
-object APIMethods400 {
- val Implementations4_0_0 = Http4s400.Implementations4_0_0
-}
-
-trait APIMethods400
-
-// ─── Original Lift implementation (commented out) ────────────────────────────
-//package code.api.v4_0_0
-//
-//import scala.language.reflectiveCalls
-//import code.DynamicData.DynamicData
-//import code.DynamicEndpoint.DynamicEndpointSwagger
-//import code.accountattribute.AccountAttributeX
-//import code.api.Constant._
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _}
-//import code.api.dynamic.endpoint.helper.practise.{DynamicEndpointCodeGenerator, PractiseEndpoint}
-//import code.api.dynamic.endpoint.helper.{CompiledObjects, DynamicEndpointHelper}
-//import code.api.dynamic.entity.helper.DynamicEntityInfo
-//import code.api.util.APIUtil.{fullBoxOrException, _}
-//import code.api.util.ApiRole._
-//import code.api.util.ApiTag._
-//import code.api.util.CommonsEmailWrapper._
-//import code.api.util.DynamicUtil.Validation
-//import code.api.util.ErrorMessages.{BankNotFound, _}
-//import code.api.util.ExampleValue._
-//import code.api.util.FutureUtil.EndpointContext
-//import code.api.util.Glossary.getGlossaryItem
-//import code.api.util.NewStyle.HttpCode
-//import code.api.util.NewStyle.function._
-//import code.api.util._
-//import code.api.util.migration.Migration
-//import code.api.util.newstyle.AttributeDefinition._
-//import code.api.util.newstyle.Consumer._
-//import code.api.util.newstyle.UserCustomerLinkNewStyle.getUserCustomerLinks
-//import code.api.util.newstyle.{BalanceNewStyle, UserCustomerLinkNewStyle, ViewNewStyle}
-//import code.api.v1_2_1.{JSONFactory, PostTransactionTagJSON}
-//import code.api.v1_4_0.JSONFactory1_4_0
-//import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
-//import code.api.v2_0_0.{CreateEntitlementJSON, CreateUserCustomerLinkJson, EntitlementJSONs, JSONFactory200}
-//import code.api.v2_1_0._
-//import code.api.v3_0_0.{CreateScopeJson, JSONFactory300}
-//import code.api.v3_1_0._
-//import code.api.v4_0_0.JSONFactory400._
-//import code.api.{Constant, JsonResponseException}
-//import code.apicollection.MappedApiCollectionsProvider
-//import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
-//import code.authtypevalidation.JsonAuthTypeValidation
-//import code.bankconnectors.LocalMappedConnectorInternal._
-//import code.bankconnectors.{Connector, DynamicConnector, InternalConnector, LocalMappedConnectorInternal}
-//import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody}
-//import code.consent.{ConsentStatus, Consents, DoobieConsentQueries}
-//import code.dynamicEntity.DynamicEntityCommons
-//import code.dynamicMessageDoc.JsonDynamicMessageDoc
-//import code.dynamicResourceDoc.JsonDynamicResourceDoc
-//import code.endpointMapping.EndpointMappingCommons
-//import code.entitlement.Entitlement
-//import code.loginattempts.LoginAttempt
-//import code.metadata.counterparties.{Counterparties, MappedCounterparty}
-//import code.metadata.tags.Tags
-//import code.model._
-//import code.model.dataAccess.{AuthUser, BankAccountCreation}
-//import code.ratelimiting.RateLimitingDI
-//import code.scope.Scope
-//// Removed: import code.snippet.{WebUIPlaceholder, WebUITemplate} - portal pages removed
-//import code.usercustomerlinks.UserCustomerLink
-//import code.userlocks.UserLocksProvider
-//import code.users.Users
-//import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN, booleanToFuture}
-//import code.util.{Helper, JsonSchemaUtil}
-//import code.validation.JsonValidation
-//import code.views.Views
-//import code.webhook.{BankAccountNotificationWebhookTrait, SystemAccountNotificationWebhookTrait}
-//import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
-//import com.github.dwickern.macros.NameOf.nameOf
-//import com.networknt.schema.ValidationMessage
-//import com.openbankproject.commons.ExecutionContext.Implicits.global
-//import com.openbankproject.commons.dto.GetProductsParam
-//import com.openbankproject.commons.model._
-//import com.openbankproject.commons.model.enums.DynamicEntityOperation._
-//import com.openbankproject.commons.model.enums.TransactionRequestTypes._
-//import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
-//import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
-//import deletion._
-//import net.liftweb.common._
-//import org.json4s.JsonAST.JValue
-//import org.json4s.JsonDSL._
-//import org.json4s._
-//import net.liftweb.util.Helpers.{now, tryo}
-//import net.liftweb.util.{Helpers, StringHelpers}
-//import org.apache.commons.lang3.StringUtils
-//
-//import java.net.URLEncoder
-//import java.text.SimpleDateFormat
-//import java.util
-//import java.util.{Calendar, Date}
-//import scala.collection.JavaConverters._
-//import scala.collection.immutable.{List, Nil}
-//import scala.collection.mutable.ArrayBuffer
-//import scala.concurrent.Future
-//
-//trait APIMethods400 extends MdcLoggable {
-// self: RestHelper =>
-//
-// val Implementations4_0_0 = new Implementations400()
-//
-// // Email template constants (moved from removed WebUITemplate/WebUIPlaceholder snippets)
-// private val EMAIL_RECIPIENT_PLACEHOLDER = "{{email_recipient}}"
-// private val ACTIVATE_ACCOUNT_PLACEHOLDER = "{{activate_your_account}}"
-// private val DEFAULT_EMAIL_TEXT = s"Dear $EMAIL_RECIPIENT_PLACEHOLDER, please activate your account: $ACTIVATE_ACCOUNT_PLACEHOLDER"
-// private val DEFAULT_EMAIL_HTML = s"Dear $EMAIL_RECIPIENT_PLACEHOLDER,
Please activate your account: Activate
"
-//
-//
-// class Implementations400 {
-//
-// val implementedInApiVersion = ApiVersion.v4_0_0
-//
-// // DRY constants for dynamic entity documentation
-// private val dynamicEntityNamingExplanation =
-// """**IMPORTANT: Entity Naming**
-// |In the examples below, "AgentConversation" and "AgentMessage" are example entity names. You should replace these with your own entity name (e.g., "Event", "Price", "Order", "Invoice"). The entity name you choose will become the API endpoint name and must be a valid identifier.""".stripMargin
-//
-// private val dynamicEntityImportantNotes =
-// """**Important Notes:**
-// |- **Entity name is your choice**: "AgentConversation", "FooBar", etc. are just examples. Replace with YOUR entity name (e.g., "Event", "Price", "Invoice")
-// |- **Entity name becomes the endpoint**: If you create an entity called "Invoice", OBP will generate endpoints like `/obp/dynamic-entity/Invoice`, `POST /obp/dynamic-entity/Invoice`, etc.
-// |- The entity name (e.g., "AgentConversation") MUST be a direct top-level key in the JSON root object
-// |- Do NOT wrap the entity in an "entity" field - this is a common mistake
-// |- Do NOT include "entityName" as a separate field
-// |- The JSON root can contain at most TWO fields: your entity name and optionally "hasPersonalEntity"
-// |- The "properties" object contains all field definitions
-// |- Each property must have "type" and "example" fields. The "description" field is optional
-// |- For boolean fields, the example must be the STRING "true" or "false" (not boolean values)
-// |- The "hasPersonalEntity" field is optional (defaults to true) and goes at the root level""".stripMargin
-//
-// private val dynamicEntityGeneratedTags =
-// """**Tags Generated for CRUD Endpoints:**
-// |When you create a dynamic entity, the resulting CRUD endpoints (GET all, GET one, POST, PUT, DELETE) will automatically be tagged with THREE tags:
-// |1. **Entity-specific tag** - Based on your entity name (e.g., "Piano", "Invoice", "AgentConversation")
-// |2. **"Dynamic-Entity"** - Groups all dynamic entity endpoints together
-// |3. **"Dynamic"** - Groups all dynamic endpoints (both entities and endpoints)
-// |
-// |These tags help organize and filter endpoints in the API Explorer.""".stripMargin
-//
-// private val dynamicEntityPianoExample =
-// """
-// |**Example 3: Piano Entity Demonstrating Different Field Types**
-// |```json
-// |{
-// | "Piano": {
-// | "description": "Piano entity with make, year, number of keys, and type",
-// | "required": ["make", "year", "number_of_keys", "is_grand", "date_purchased", "weight_in_kg"],
-// | "properties": {
-// | "make": {
-// | "type": "string",
-// | "example": "Steinway"
-// | },
-// | "year": {
-// | "type": "string",
-// | "example": "2023"
-// | },
-// | "number_of_keys": {
-// | "type": "integer",
-// | "example": 88
-// | },
-// | "is_grand": {
-// | "type": "boolean",
-// | "example": "true"
-// | },
-// | "date_purchased": {
-// | "type": "DATE_WITH_DAY",
-// | "example": "2023-06-15"
-// | },
-// | "weight_in_kg": {
-// | "type": "number",
-// | "example": 480.5
-// | }
-// | }
-// | },
-// | "hasPersonalEntity": true
-// |}
-// |```""".stripMargin
-//
-// private val staticResourceDocs = ArrayBuffer[ResourceDoc]()
-// // createDynamicEntityDoc and updateDynamicEntityDoc are dynamic, So here dynamic create resourceDocs
-// def resourceDocs = staticResourceDocs ++ ArrayBuffer[ResourceDoc](
-// createDynamicEntityDoc,
-// createBankLevelDynamicEntityDoc,
-// updateDynamicEntityDoc,
-// updateBankLevelDynamicEntityDoc,
-// updateMyDynamicEntityDoc
-// )
-//
-// val apiRelations = ArrayBuffer[ApiRelation]()
-// val codeContext = CodeContext(staticResourceDocs, apiRelations)
-//
-// staticResourceDocs += ResourceDoc(
-// getMapperDatabaseInfo,
-// implementedInApiVersion,
-// nameOf(getMapperDatabaseInfo),
-// "GET",
-// "/database/info",
-// "Get Mapper Database Info",
-// s"""Get basic information about the Mapper Database.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// adapterInfoJsonV300,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagApi),
-// Some(List(canGetDatabaseInfo))
-// )
-//
-// lazy val getMapperDatabaseInfo: OBPEndpoint = {
-// case "database" :: "info" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// Future {
-// (
-// Migration.DbFunction.mapperDatabaseInfo,
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getLogoutLink,
-// implementedInApiVersion,
-// nameOf(
-// getLogoutLink
-// ), // TODO can we get this string from the val two lines above?
-// "GET",
-// "/users/current/logout-link",
-// "Get Logout Link",
-// s"""Get the Logout Link
-// |
-// |${userAuthenticationMessage(true)}
-// """.stripMargin,
-// EmptyBody,
-// logoutLinkV400,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagUser)
-// )
-//
-// lazy val getLogoutLink: OBPEndpoint = {
-// case "users" :: "current" :: "logout-link" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// Future {
-// val link = code.api.Constant.HostName + AuthUser.logoutPath.foldLeft(
-// ""
-// )(_ + "/" + _)
-// val logoutLink = LogoutLinkJson(link)
-// (logoutLink, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// callsLimit,
-// implementedInApiVersion,
-// nameOf(callsLimit),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/call-limits",
-// "Set Rate Limits / Call Limits per Consumer",
-// s"""
-// |Set the API rate limits / call limits for a Consumer:
-// |
-// |Rate limiting can be set:
-// |
-// |Per Second
-// |Per Minute
-// |Per Hour
-// |Per Week
-// |Per Month
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// callLimitPostJsonV400,
-// callLimitPostJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer, apiTagRateLimits),
-// Some(List(canUpdateRateLimits))
-// )
-//
-// lazy val callsLimit: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.handleEntitlementsAndScopes(
-// "",
-// u.userId,
-// List(canUpdateRateLimits),
-// callContext
-// )
-// postJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $CallLimitPostJsonV400 ",
-// 400,
-// callContext
-// ) {
-// json.extract[CallLimitPostJsonV400]
-// }
-// _ <- NewStyle.function.getConsumerByConsumerId(
-// consumerId,
-// callContext
-// )
-// rateLimiting <- RateLimitingDI.rateLimiting.vend
-// .createOrUpdateConsumerCallLimits(
-// consumerId,
-// postJson.from_date,
-// postJson.to_date,
-// postJson.api_version,
-// postJson.api_name,
-// postJson.bank_id,
-// Some(postJson.per_second_call_limit),
-// Some(postJson.per_minute_call_limit),
-// Some(postJson.per_hour_call_limit),
-// Some(postJson.per_day_call_limit),
-// Some(postJson.per_week_call_limit),
-// Some(postJson.per_month_call_limit)
-// ) map {
-// unboxFullOrFail(_, callContext, UpdateConsumerError)
-// }
-// } yield {
-// (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBanks,
-// implementedInApiVersion,
-// nameOf(getBanks),
-// "GET",
-// "/banks",
-// "Get Banks",
-// """Get banks on this API instance
-// |Returns a list of banks supported on this server:
-// |
-// |* ID used as parameter in URLs
-// |* Short and full name of bank
-// |* Logo URL
-// |* Website""",
-// EmptyBody,
-// banksJSON400,
-// List(UnknownError),
-// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBanks: OBPEndpoint = {
-// case "banks" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (banks, callContext) <- NewStyle.function.getBanks(cc.callContext)
-// } yield {
-// (JSONFactory400.createBanksJson(banks), HttpCode.`200`(callContext))
-// }
-//
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBank,
-// implementedInApiVersion,
-// nameOf(getBank),
-// "GET",
-// "/banks/BANK_ID",
-// "Get Bank",
-// """Get the bank specified by BANK_ID
-// |Returns information about a single bank specified by BANK_ID including:
-// |
-// |* Short and full name of bank
-// |* Logo URL
-// |* Website""",
-// EmptyBody,
-// bankJson400,
-// List(UnknownError, BankNotFound),
-// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (bank, callContext) <- NewStyle.function.getBank(
-// bankId,
-// cc.callContext
-// )
-// (attributes, callContext) <- NewStyle.function
-// .getBankAttributesByBank(bankId, callContext)
-// } yield (
-// JSONFactory400.createBankJSON400(bank, attributes),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// ibanChecker,
-// implementedInApiVersion,
-// nameOf(ibanChecker),
-// "POST",
-// "/account/check/scheme/iban",
-// "Validate and check IBAN",
-// """Validate and check IBAN for errors
-// |
-// |""",
-// ibanCheckerPostJsonV400,
-// ibanCheckerJsonV400,
-// List(UnknownError),
-// apiTagAccount :: Nil
-// )
-//
-// lazy val ibanChecker: OBPEndpoint = {
-// case "account" :: "check" :: "scheme" :: "iban" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(ibanCheckerPostJsonV400))}"
-// for {
-// ibanJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[IbanAddress]
-// }
-// (ibanChecker, callContext) <- NewStyle.function
-// .validateAndCheckIbanNumber(ibanJson.address, cc.callContext)
-// } yield {
-// (
-// JSONFactory400.createIbanCheckerJson(ibanChecker),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDoubleEntryTransaction,
-// implementedInApiVersion,
-// nameOf(getDoubleEntryTransaction),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/double-entry-transaction",
-// "Get Double Entry Transaction",
-// s"""Get Double Entry Transaction
-// |
-// |This endpoint can be used to see the double entry transactions. It returns the `bank_id`, `account_id` and `transaction_id`
-// |for the debit end the credit transaction. The other side account can be a settlement account or an OBP account.
-// |
-// |The endpoint also provide the `transaction_request` object which contains the `bank_id`, `account_id` and
-// |`transaction_request_id` of the transaction request at the origin of the transaction. Please note that if none
-// |transaction request is at the origin of the transaction, the `transaction_request` object will be `null`.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// doubleEntryTransactionJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction),
-// Some(
-// List(
-// canGetDoubleEntryTransactionAtAnyBank,
-// canGetDoubleEntryTransactionAtOneBank
-// )
-// )
-// )
-//
-// lazy val getDoubleEntryTransaction: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transactions" :: TransactionId(
-// transactionId
-// ) :: "double-entry-transaction" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// (doubleEntryTransaction, callContext) <- NewStyle.function
-// .getDoubleEntryBookTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createDoubleEntryTransactionJson(
-// doubleEntryTransaction
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// getBalancingTransaction,
-// implementedInApiVersion,
-// nameOf(getBalancingTransaction),
-// "GET",
-// "/transactions/TRANSACTION_ID/balancing-transaction",
-// "Get Balancing Transaction",
-// s"""Get Balancing Transaction
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// doubleEntryTransactionJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction),
-// Some(List())
-// )
-//
-// lazy val getBalancingTransaction: OBPEndpoint = {
-// case "transactions" :: TransactionId(
-// transactionId
-// ) :: "balancing-transaction" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (doubleEntryTransaction, callContext) <- NewStyle.function
-// .getBalancingTransaction(transactionId, cc.callContext)
-// _ <- ViewNewStyle.checkBalancingTransactionAccountAccessAndReturnView(
-// doubleEntryTransaction,
-// cc.user,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createDoubleEntryTransactionJson(
-// doubleEntryTransaction
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createSettlementAccount,
-// implementedInApiVersion,
-// nameOf(createSettlementAccount),
-// "POST",
-// "/banks/BANK_ID/settlement-accounts",
-// "Create Settlement Account",
-// s"""Create a new settlement account at a bank.
-// |
-// |The created settlement account id will be the concatenation of the payment system and the account currency.
-// |For examples: SEPA_SETTLEMENT_ACCOUNT_EUR, CARD_SETTLEMENT_ACCOUNT_USD
-// |
-// |By default, when you create a new bank, two settlements accounts are created automatically: OBP_DEFAULT_INCOMING_ACCOUNT_ID and OBP_DEFAULT_OUTGOING_ACCOUNT_ID
-// |Those two accounts have EUR as default currency.
-// |
-// |If you want to create default settlement account for a specific currency, you can fill the `payment_system` field with the `DEFAULT` value.
-// |
-// |When a transaction is saved in OBP through the mapped connector, OBP-API look for the account to save the double-entry transaction.
-// |If no OBP account can be found from the counterparty, the double-entry transaction will be saved on a bank settlement account.
-// |- First, the mapped connector looks for a settlement account specific to the payment system and currency. E.g SEPA_SETTLEMENT_ACCOUNT_EUR.
-// |- If we don't find any specific settlement account with the payment system, we look for a default settlement account for the counterparty currency. E.g DEFAULT_SETTLEMENT_ACCOUNT_EUR.
-// |- Else, we select one of the two OBP default settlement accounts (OBP_DEFAULT_INCOMING_ACCOUNT_ID/OBP_DEFAULT_OUTGOING_ACCOUNT_ID) according to the transaction direction.
-// |
-// |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.
-// |
-// |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User.
-// |
-// |Note: The Amount MUST be zero.
-// |""".stripMargin,
-// settlementAccountRequestJson,
-// settlementAccountResponseJson,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidAccountInitialBalance,
-// InitialBalanceMustBeZero,
-// InvalidISOCurrencyCode,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canCreateSettlementAccountAtOneBank))
-// )
-//
-// lazy val createSettlementAccount: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "settlement-accounts" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(settlementAccountRequestJson))}"
-// for {
-// createAccountJson <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[SettlementAccountRequestJson]
-// }
-// loggedInUserId = cc.userId
-// userIdAccountOwner =
-// if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id
-// else loggedInUserId
-// (postedOrLoggedInUser, callContext) <- NewStyle.function.findByUserId(
-// userIdAccountOwner,
-// cc.callContext
-// )
-//
-// _ <-
-// if (userIdAccountOwner == loggedInUserId)
-// Future.successful(Full(Unit))
-// else
-// NewStyle.function.hasEntitlement(
-// bankId.value,
-// loggedInUserId,
-// canCreateSettlementAccountAtOneBank,
-// callContext
-// )
-//
-// initialBalanceAsString = createAccountJson.balance.amount
-// accountLabel = createAccountJson.label
-// initialBalanceAsNumber <- NewStyle.function.tryons(
-// InvalidAccountInitialBalance,
-// 400,
-// callContext
-// ) {
-// BigDecimal(initialBalanceAsString)
-// }
-// _ <- Helper.booleanToFuture(
-// InitialBalanceMustBeZero,
-// cc = callContext
-// ) { 0 == initialBalanceAsNumber }
-// currency = createAccountJson.balance.currency
-// _ <- Helper.booleanToFuture(
-// InvalidISOCurrencyCode,
-// cc = callContext
-// ) { APIUtil.isValidCurrencyISOCode(currency) }
-//
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(
-// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme",
-// cc = callContext
-// ) {
-// createAccountJson.account_routings
-// .map(_.scheme)
-// .distinct
-// .size == createAccountJson.account_routings.size
-// }
-// alreadyExistAccountRoutings <- Future.sequence(
-// createAccountJson.account_routings.map(accountRouting =>
-// NewStyle.function
-// .getAccountRouting(
-// Some(bankId),
-// accountRouting.scheme,
-// accountRouting.address,
-// callContext
-// )
-// .map(_ => Some(accountRouting))
-// .fallbackTo(Future.successful(None))
-// )
-// )
-// alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
-// case Some(accountRouting) =>
-// s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
-// }
-// _ <- Helper.booleanToFuture(
-// s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})",
-// cc = callContext
-// ) {
-// alreadyExistingAccountRouting.isEmpty
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme",
-// cc = callContext
-// ) {
-// createAccountJson.account_routings
-// .map(_.scheme)
-// .distinct
-// .size == createAccountJson.account_routings.size
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidPaymentSystemName Space characters are not allowed.",
-// cc = callContext
-// ) {
-// !createAccountJson.payment_system.contains(" ")
-// }
-// accountId = AccountId(
-// createAccountJson.payment_system.toUpperCase + "_SETTLEMENT_ACCOUNT_" + currency.toUpperCase
-// )
-// (bankAccount, callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// accountId,
-// "SETTLEMENT",
-// accountLabel,
-// currency,
-// initialBalanceAsNumber,
-// postedOrLoggedInUser.name,
-// createAccountJson.branch_id,
-// createAccountJson.account_routings.map(r =>
-// AccountRouting(r.scheme, r.address)
-// ),
-// callContext
-// )
-// accountId = bankAccount.accountId
-// (productAttributes, callContext) <- NewStyle.function
-// .getProductAttributesByBankAndCode(
-// bankId,
-// ProductCode("SETTLEMENT"),
-// callContext
-// )
-// (accountAttributes, callContext) <- NewStyle.function
-// .createAccountAttributes(
-// bankId,
-// accountId,
-// ProductCode("SETTLEMENT"),
-// productAttributes,
-// None,
-// callContext: Option[CallContext]
-// )
-// // 1 Create or Update the `Owner` for the new account
-// // 2 Add permission to the user
-// // 3 Set the user as the account holder
-// _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(
-// bankId,
-// accountId,
-// postedOrLoggedInUser,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createSettlementAccountJson(
-// userIdAccountOwner,
-// bankAccount,
-// accountAttributes
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSettlementAccounts,
-// implementedInApiVersion,
-// nameOf(getSettlementAccounts),
-// "GET",
-// "/banks/BANK_ID/settlement-accounts",
-// "Get Settlement accounts at Bank",
-// """Get settlement accounts on this API instance
-// |Returns a list of settlement accounts at this Bank
-// |
-// |Note: a settlement account is considered as a bank account.
-// |So you can update it and add account attributes to it using the regular account endpoints
-// |""",
-// EmptyBody,
-// settlementAccountsJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagPsd2),
-// Some(List(canGetSettlementAccountAtOneBank))
-// )
-//
-// lazy val getSettlementAccounts: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "settlement-accounts" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.hasEntitlement(
-// bankId.value,
-// cc.userId,
-// canGetSettlementAccountAtOneBank,
-// cc.callContext
-// )
-//
-// (accounts, callContext) <- NewStyle.function
-// .getBankSettlementAccounts(bankId, cc.callContext)
-// settlementAccounts <- Future.sequence(accounts.map(account => {
-// NewStyle.function
-// .getAccountAttributesByAccount(
-// bankId,
-// account.accountId,
-// callContext
-// )
-// .map(accountAttributes =>
-// JSONFactory400
-// .getSettlementAccountJson(account, accountAttributes._1)
-// )
-// }))
-// } yield {
-// (
-// SettlementAccountsJson(settlementAccounts),
-// HttpCode.`200`(callContext)
-// )
-// }
-//
-// }
-// }
-//
-// // ACCOUNT. (we no longer create a resource doc for the general case)
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestAccount,
-// implementedInApiVersion,
-// "createTransactionRequestAccount",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT/transaction-requests",
-// "Create Transaction Request (ACCOUNT)",
-// s"""When using ACCOUNT, the payee is set in the request body.
-// |
-// |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body.
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyJsonV200,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// // ACCOUNT_OTP. (we no longer create a resource doc for the general case)
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestAccountOtp,
-// implementedInApiVersion,
-// "createTransactionRequestAccountOtp",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT_OTP/transaction-requests",
-// "Create Transaction Request (ACCOUNT_OTP)",
-// s"""When using ACCOUNT, the payee is set in the request body.
-// |
-// |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body.
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyJsonV200,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// // COUNTERPARTY
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestCounterparty,
-// implementedInApiVersion,
-// "createTransactionRequestCounterparty",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/COUNTERPARTY/transaction-requests",
-// "Create Transaction Request (COUNTERPARTY)",
-// s"""
-// |$transactionRequestGeneralText
-// |
-// |When using a COUNTERPARTY to create a Transaction Request, specify the counterparty_id in the body of the request.
-// |The routing details of the counterparty will be forwarded to the Core Banking System (CBS) for the transfer.
-// |
-// |COUNTERPARTY Transaction Requests are used for Variable Recurring Payments (VRP). Use the following ${Glossary
-// .getApiExplorerLink(
-// "endpoint",
-// "OBPv5.1.0-createVRPConsentRequest"
-// )} to create a consent for VRPs.
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// """.stripMargin,
-// transactionRequestBodyCounterpartyJSON,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// // SIMPLE
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestSimple,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestSimple),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SIMPLE/transaction-requests",
-// "Create Transaction Request (SIMPLE)",
-// s"""
-// |Special instructions for SIMPLE:
-// |
-// |You can transfer money to the Bank Account Number or IBAN directly.
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodySimpleJsonV400,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// // Transaction Request (SEPA)
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestSepa,
-// implementedInApiVersion,
-// "createTransactionRequestSepa",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SEPA/transaction-requests",
-// "Create Transaction Request (SEPA)",
-// s"""
-// |Special instructions for SEPA:
-// |
-// |When using a SEPA Transaction Request, you specify the IBAN of a Counterparty in the body of the request.
-// |The routing details (IBAN) of the counterparty will be forwarded to the core banking system for the transfer.
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodySEPAJsonV400,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestRefund,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestRefund),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/REFUND/transaction-requests",
-// "Create Transaction Request (REFUND)",
-// s"""
-// |
-// |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded.
-// |
-// |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction.
-// |In the `from` object, you have two choices :
-// |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API
-// |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API
-// |
-// |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent.
-// |(This case is not managed by the OBP-API and require an external adapter)
-// |
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyRefundJsonV400,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// // FREE_FORM.
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestFreeForm,
-// implementedInApiVersion,
-// "createTransactionRequestFreeForm",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/FREE_FORM/transaction-requests",
-// "Create Transaction Request (FREE_FORM)",
-// s"""$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyFreeFormJSON,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS),
-// Some(List(canCreateAnyTransactionRequest))
-// )
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestAgentCashWithDrawal,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestAgentCashWithDrawal),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/AGENT_CASH_WITHDRAWAL/transaction-requests",
-// "Create Transaction Request (AGENT_CASH_WITHDRAWAL)",
-// s"""
-// |
-// |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded.
-// |
-// |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction.
-// |In the `from` object, you have two choices :
-// |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API
-// |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API
-// |
-// |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent.
-// |(This case is not managed by the OBP-API and require an external adapter)
-// |
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyAgentJsonV400,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestAgentCashWithDrawal: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "AGENT_CASH_WITHDRAWAL" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType(
-// "AGENT_CASH_WITHDRAWAL"
-// )
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestAccount: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "ACCOUNT" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("ACCOUNT")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestAccountOtp: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "ACCOUNT_OTP" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("ACCOUNT_OTP")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestSepa: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "SEPA" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("SEPA")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestCounterparty: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "COUNTERPARTY" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("COUNTERPARTY")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestRefund: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "REFUND" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("REFUND")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestFreeForm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "FREE_FORM" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("FREE_FORM")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// lazy val createTransactionRequestSimple: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// "SIMPLE" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("SIMPLE")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transactionRequestType,
-// json
-// )
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestCard,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestCard),
-// "POST",
-// "/transaction-request-types/CARD/transaction-requests",
-// "Create Transaction Request (CARD)",
-// s"""
-// |
-// |When using CARD, the payee is set in the request body .
-// |
-// |Money goes into the Counterparty in the request body.
-// |
-// |$transactionRequestGeneralText
-// |
-// """.stripMargin,
-// transactionRequestBodyCardJsonV400,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// AccountNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestCard: OBPEndpoint = {
-// case "transaction-request-types" :: "CARD" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("CARD")
-// LocalMappedConnectorInternal.createTransactionRequest(
-// BankId(""),
-// AccountId(""),
-// ViewId(Constant.SYSTEM_OWNER_VIEW_ID),
-// transactionRequestType,
-// json
-// )
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// answerTransactionRequestChallenge,
-// implementedInApiVersion,
-// "answerTransactionRequestChallenge",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge",
-// "Answer Transaction Request Challenge",
-// s"""In Sandbox mode, any string that can be converted to a positive integer will be accepted as an answer.
-// |
-// |This endpoint totally depends on createTransactionRequest, it need get the following data from createTransactionRequest response body.
-// |
-// |1)`TRANSACTION_REQUEST_TYPE` : is the same as createTransactionRequest request URL .
-// |
-// |2)`TRANSACTION_REQUEST_ID` : is the `id` field in createTransactionRequest response body.
-// |
-// |3) `id` : is `challenge.id` field in createTransactionRequest response body.
-// |
-// |4) `answer` : must be `123` in case that Strong Customer Authentication method for OTP challenge is dummy.
-// | For instance: SANDBOX_TAN_OTP_INSTRUCTION_TRANSPORT=dummy
-// | Possible values are dummy,email and sms
-// | In CBS mode, the answer can be got by phone message or other SCA methods.
-// |
-// |Note that each Transaction Request Type can have its own OTP_INSTRUCTION_TRANSPORT method.
-// |OTP_INSTRUCTION_TRANSPORT methods are set in Props. See sample.props.template for instructions.
-// |
-// |Single or Multiple authorisations
-// |
-// |OBP allows single or multi party authorisations.
-// |
-// |Single party authorisation:
-// |
-// |In the case that only one person needs to authorise i.e. answer a security challenge we have the following change of state of a `transaction request`:
-// | INITIATED => COMPLETED
-// |
-// |
-// |Multiparty authorisation:
-// |
-// |In the case that multiple parties (n persons) need to authorise a transaction request i.e. answer security challenges, we have the followings state flow for a `transaction request`:
-// | INITIATED => NEXT_CHALLENGE_PENDING => ... => NEXT_CHALLENGE_PENDING => COMPLETED
-// |
-// |The security challenge is bound to a user i.e. in the case of a correct answer but the user is different than expected the challenge will fail.
-// |
-// |Rule for calculating number of security challenges:
-// |If Product Account attribute REQUIRED_CHALLENGE_ANSWERS=N then create N challenges
-// |(one for every user that has a View where permission $CAN_ADD_TRANSACTION_REQUEST_TO_ANY_ACCOUNT=true)
-// |In the case REQUIRED_CHALLENGE_ANSWERS is not defined as an account attribute, the default number of security challenges created is one.
-// |
-// """.stripMargin,
-// challengeAnswerJson400,
-// transactionRequestWithChargeJSON210,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// InvalidAccountIdFormat,
-// InvalidJsonFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// TransactionRequestStatusNotInitiated,
-// TransactionRequestTypeHasChanged,
-// AllowedAttemptsUsedUp,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val answerTransactionRequestChallenge: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-request-types" ::
-// TransactionRequestType(
-// transactionRequestType
-// ) :: "transaction-requests" :: TransactionRequestId(
-// transReqId
-// ) :: "challenge" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, fromAccount, callContext) <- SS.userBankAccount
-// _ <- NewStyle.function.isEnabledTransactionRequests(callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidAccountIdFormat,
-// cc = callContext
-// ) {
-// isValidID(accountId.value)
-// }
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) {
-// isValidID(bankId.value)
-// }
-// challengeAnswerJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $ChallengeAnswerJson400",
-// 400,
-// callContext
-// ) {
-// json.extract[ChallengeAnswerJson400]
-// }
-//
-// account = BankIdAccountId(fromAccount.bankId, fromAccount.accountId)
-// _ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(
-// viewId,
-// account,
-// u,
-// callContext
-// )
-//
-// // Check transReqId is valid
-// (existingTransactionRequest, callContext) <- NewStyle.function
-// .getTransactionRequestImpl(transReqId, callContext)
-//
-// // Check the Transaction Request is still INITIATED or NEXT_CHALLENGE_PENDING or FORWARDED
-// _ <- Helper.booleanToFuture(
-// TransactionRequestStatusNotInitiatedOrPendingOrForwarded,
-// cc = callContext
-// ) {
-// existingTransactionRequest.status.equals(
-// TransactionRequestStatus.INITIATED.toString
-// ) ||
-// existingTransactionRequest.status.equals(
-// TransactionRequestStatus.NEXT_CHALLENGE_PENDING.toString
-// ) ||
-// existingTransactionRequest.status.equals(
-// TransactionRequestStatus.FORWARDED.toString
-// )
-// }
-//
-// // Check Maker/Checker separation if required by the view
-// _ <- NewStyle.function.checkMakerCheckerForTransactionRequest(
-// bankId,
-// accountId,
-// viewId,
-// transReqId,
-// challengeAnswerJson.id,
-// u.userId,
-// callContext
-// )
-//
-// // Check the input transactionRequestType is the same as when the user created the TransactionRequest
-// existingTransactionRequestType = existingTransactionRequest.`type`
-// _ <- Helper.booleanToFuture(
-// s"${TransactionRequestTypeHasChanged} It should be :'$existingTransactionRequestType', but current value (${transactionRequestType.value}) ",
-// cc = callContext
-// ) {
-// existingTransactionRequestType.equals(transactionRequestType.value)
-// }
-//
-// (challenges, callContext) <- NewStyle.function
-// .getChallengesByTransactionRequestId(transReqId.value, callContext)
-//
-// // Check the challenge type, Note: not supported yet, the default value is SANDBOX_TAN
-// _ <- Helper.booleanToFuture(
-// s"$InvalidChallengeType Current Type is ${challenges.map(_.challengeType)}",
-// cc = callContext
-// ) {
-// challenges
-// .map(_.challengeType)
-// .filterNot(challengeType =>
-// challengeType.equals(
-// ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE.toString
-// )
-// )
-// .isEmpty
-// }
-//
-// (transactionRequest, callContext) <-
-// challengeAnswerJson.answer match {
-// // If the challenge answer is `REJECT` - Currently only to Reject a SEPA transaction request REFUND
-// case "REJECT" =>
-// val transactionRequest =
-// existingTransactionRequest.copy(status =
-// TransactionRequestStatus.REJECTED.toString
-// )
-// for {
-// (fromAccount, toAccount, callContext) <- {
-// // If the transaction request comes from the account to debit
-// if (
-// fromAccount.accountId.value == transactionRequest.from.account_id
-// ) {
-// val toCounterpartyIban =
-// transactionRequest.other_account_routing_address
-// for {
-// (toCounterparty, callContext) <- NewStyle.function
-// .getCounterpartyByIbanAndBankAccountId(
-// toCounterpartyIban,
-// fromAccount.bankId,
-// fromAccount.accountId,
-// callContext
-// )
-// (toAccount, callContext) <- NewStyle.function
-// .getBankAccountFromCounterparty(
-// toCounterparty,
-// true,
-// callContext
-// )
-// } yield (fromAccount, toAccount, callContext)
-// } else {
-// // Else, the transaction request debit a counterparty (Iban)
-// val fromCounterpartyIban =
-// transactionRequest.from.account_id
-// // and the creditor is the obp account owner
-// val toAccount = fromAccount
-// for {
-// (fromCounterparty, callContext) <- NewStyle.function
-// .getCounterpartyByIbanAndBankAccountId(
-// fromCounterpartyIban,
-// toAccount.bankId,
-// toAccount.accountId,
-// callContext
-// )
-// (fromAccount, callContext) <- NewStyle.function
-// .getBankAccountFromCounterparty(
-// fromCounterparty,
-// false,
-// callContext
-// )
-// } yield (fromAccount, toAccount, callContext)
-// }
-// }
-// rejectReasonCode = challengeAnswerJson.reason_code.getOrElse(
-// ""
-// )
-// _ <-
-// if (rejectReasonCode.nonEmpty) {
-// NewStyle.function
-// .createOrUpdateTransactionRequestAttribute(
-// bankId = bankId,
-// transactionRequestId = transactionRequest.id,
-// transactionRequestAttributeId = None,
-// name = "reject_reason_code",
-// attributeType =
-// TransactionRequestAttributeType.withName("STRING"),
-// value = rejectReasonCode,
-// callContext = callContext
-// )
-// } else Future.successful(())
-// rejectAdditionalInformation =
-// challengeAnswerJson.additional_information.getOrElse("")
-// _ <-
-// if (rejectAdditionalInformation.nonEmpty) {
-// NewStyle.function
-// .createOrUpdateTransactionRequestAttribute(
-// bankId = bankId,
-// transactionRequestId = transactionRequest.id,
-// transactionRequestAttributeId = None,
-// name = "reject_additional_information",
-// attributeType =
-// TransactionRequestAttributeType.withName("STRING"),
-// value = rejectAdditionalInformation,
-// callContext = callContext
-// )
-// } else Future.successful(())
-// _ <- NewStyle.function.notifyTransactionRequest(
-// fromAccount,
-// toAccount,
-// transactionRequest,
-// callContext
-// )
-// _ <- NewStyle.function.saveTransactionRequestStatusImpl(
-// transactionRequest.id,
-// transactionRequest.status,
-// callContext
-// )
-// } yield (transactionRequest, callContext)
-// case _ =>
-// // Determine if the current user is answering their own assigned challenge
-// val challengeToAnswer = challenges.find(_.challengeId == challengeAnswerJson.id)
-// val isAnsweringOwnChallenge = challengeToAnswer.exists(_.expectedUserId == u.userId)
-//
-// for {
-//
-// (challengeAnswerIsValidated, callContext) <- if (isAnsweringOwnChallenge) {
-// // User is answering their own challenge — validate with userId check
-// NewStyle.function.validateChallengeAnswer(
-// challengeAnswerJson.id,
-// challengeAnswerJson.answer,
-// SuppliedAnswerType.PLAIN_TEXT_VALUE,
-// callContext
-// )
-// } else {
-// // User is answering someone else's challenge (checker answering maker's challenge)
-// // Safe because maker-checker check already approved this user
-// NewStyle.function.validateChallengeAnswerWithoutUserIdCheck(
-// challengeAnswerJson.id,
-// challengeAnswerJson.answer,
-// SuppliedAnswerType.PLAIN_TEXT_VALUE,
-// callContext
-// )
-// }
-//
-// _ <- Helper.booleanToFuture(
-// s"${InvalidChallengeAnswer
-// .replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
-// .replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")}",
-// cc = callContext
-// ) {
-// challengeAnswerIsValidated
-// }
-//
-// (challengeAnswerIsValidated, callContext) <- NewStyle.function
-// .allChallengesSuccessfullyAnswered(
-// bankId,
-// accountId,
-// transReqId,
-// callContext
-// )
-// _ <- Helper.booleanToFuture(
-// s"$NextChallengePending",
-// cc = callContext
-// ) {
-// challengeAnswerIsValidated
-// }
-// (transactionRequest, callContext) <- TransactionRequestTypes
-// .withName(transactionRequestType.value) match {
-// case TRANSFER_TO_PHONE | TRANSFER_TO_ATM |
-// TRANSFER_TO_ACCOUNT =>
-// NewStyle.function.createTransactionAfterChallengeV300(
-// u,
-// fromAccount,
-// transReqId,
-// transactionRequestType,
-// callContext
-// )
-// case _ =>
-// NewStyle.function.createTransactionAfterChallengeV210(
-// fromAccount,
-// existingTransactionRequest,
-// callContext
-// )
-// }
-// } yield (transactionRequest, callContext)
-// }
-//
-// (transactionRequestAttribute, callContext) <- NewStyle.function
-// .getTransactionRequestAttributes(
-// bankId,
-// transactionRequest.id,
-// callContext
-// )
-// } yield {
-//
-// (
-// JSONFactory400.createTransactionRequestWithChargeJSON(
-// transactionRequest,
-// challenges,
-// transactionRequestAttribute
-// ),
-// HttpCode.`202`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestAttribute,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestAttribute),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attribute",
-// "Create Transaction Request Attribute",
-// s""" Create Transaction Request Attribute
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionRequestAttributeJsonV400,
-// transactionRequestAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canCreateTransactionRequestAttributeAtOneBank))
-// )
-//
-// lazy val createTransactionRequestAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transaction-requests" :: TransactionRequestId(
-// transactionRequestId
-// ) :: "attribute" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $transactionRequestAttributeJsonV400 "
-// for {
-// (_, callContext) <- NewStyle.function.getTransactionRequestImpl(
-// transactionRequestId,
-// cc.callContext
-// )
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[TransactionRequestAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// transactionRequestAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// TransactionRequestAttributeType.withName(postedData.attribute_type)
-// }
-// (transactionRequestAttribute, callContext) <- NewStyle.function
-// .createOrUpdateTransactionRequestAttribute(
-// bankId,
-// transactionRequestId,
-// None,
-// postedData.name,
-// transactionRequestAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionRequestAttributeJson(
-// transactionRequestAttribute
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionRequestAttributeById,
-// implementedInApiVersion,
-// nameOf(getTransactionRequestAttributeById),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID",
-// "Get Transaction Request Attribute By Id",
-// s""" Get Transaction Request Attribute By Id
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionRequestAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canGetTransactionRequestAttributeAtOneBank))
-// )
-//
-// lazy val getTransactionRequestAttributeById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transaction-requests" :: TransactionRequestId(
-// transactionRequestId
-// ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getTransactionRequestImpl(
-// transactionRequestId,
-// cc.callContext
-// )
-// (transactionRequestAttribute, callContext) <- NewStyle.function
-// .getTransactionRequestAttributeById(
-// transactionRequestAttributeId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionRequestAttributeJson(
-// transactionRequestAttribute
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionRequestAttributes,
-// implementedInApiVersion,
-// nameOf(getTransactionRequestAttributes),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes",
-// "Get Transaction Request Attributes",
-// s""" Get Transaction Request Attributes
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionRequestAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canGetTransactionRequestAttributesAtOneBank))
-// )
-//
-// lazy val getTransactionRequestAttributes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transaction-requests" :: TransactionRequestId(
-// transactionRequestId
-// ) :: "attributes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getTransactionRequestImpl(
-// transactionRequestId,
-// cc.callContext
-// )
-// (transactionRequestAttribute, callContext) <- NewStyle.function
-// .getTransactionRequestAttributes(
-// bankId,
-// transactionRequestId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionRequestAttributesJson(
-// transactionRequestAttribute
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateTransactionRequestAttribute,
-// implementedInApiVersion,
-// nameOf(updateTransactionRequestAttribute),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID",
-// "Update Transaction Request Attribute",
-// s""" Update Transaction Request Attribute
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionRequestAttributeJsonV400,
-// transactionRequestAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canUpdateTransactionRequestAttributeAtOneBank))
-// )
-//
-// lazy val updateTransactionRequestAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transaction-requests" :: TransactionRequestId(
-// transactionRequestId
-// ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $TransactionRequestAttributeJsonV400"
-// for {
-// (_, callContext) <- NewStyle.function.getTransactionRequestImpl(
-// transactionRequestId,
-// cc.callContext
-// )
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[TransactionRequestAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// transactionRequestAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// TransactionRequestAttributeType.withName(
-// postedData.attribute_type
-// )
-// }
-// (_, callContext) <- NewStyle.function
-// .getTransactionRequestAttributeById(
-// transactionRequestAttributeId,
-// callContext
-// )
-// (transactionRequestAttribute, callContext) <- NewStyle.function
-// .createOrUpdateTransactionRequestAttribute(
-// bankId,
-// transactionRequestId,
-// Some(transactionRequestAttributeId),
-// postedData.name,
-// transactionRequestAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionRequestAttributeJson(
-// transactionRequestAttribute
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateTransactionRequestAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateTransactionRequestAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/transaction-request",
-// "Create or Update Transaction Request Attribute Definition",
-// s""" Create or Update Transaction Request Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.TransactionRequest}
-// |
-// |The type field must be one of: ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionRequestAttributeDefinitionJsonV400,
-// transactionRequestAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canCreateTransactionRequestAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateTransactionRequestAttributeDefinition
-// : OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER}(123) and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.TransactionRequest}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionRequestAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getTransactionRequestAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/transaction-request",
-// "Get Transaction Request Attribute Definition",
-// s""" Get Transaction Request Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionRequestAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canGetTransactionRequestAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getTransactionRequestAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(
-// AttributeCategory.TransactionRequest.toString
-// ),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(
-// attributeDefinitions
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteTransactionRequestAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteTransactionRequestAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction-request",
-// "Delete Transaction Request Attribute Definition",
-// s""" Delete Transaction Request Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute),
-// Some(List(canDeleteTransactionRequestAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteTransactionRequestAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction-request" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(
-// AttributeCategory.TransactionRequest.toString
-// ),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getSystemDynamicEntities),
-// "GET",
-// "/management/system-dynamic-entities",
-// "Get System Dynamic Entities",
-// s"""Get all System Dynamic Entities.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )} """,
-// EmptyBody,
-// ListResult(
-// "dynamic_entities",
-// List(dynamicEntityResponseBodyExample)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canGetSystemLevelDynamicEntities))
-// )
-//
-// lazy val getSystemDynamicEntities: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntities(None, false)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities
-// val jObjects = listCommons.map(_.jValue)
-// (
-// ListResult("dynamic_entities", jObjects),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicEntities),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-entities",
-// "Get Bank Level Dynamic Entities",
-// s"""Get all the bank level Dynamic Entities for one bank.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}""",
-// EmptyBody,
-// ListResult(
-// "dynamic_entities",
-// List(dynamicEntityResponseBodyExample)
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities))
-// )
-//
-// lazy val getBankLevelDynamicEntities: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntities(Some(bankId), false)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities
-// val jObjects = listCommons.map(_.jValue)
-// (
-// ListResult("dynamic_entities", jObjects),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// private def createDynamicEntityMethod(
-// cc: CallContext,
-// dynamicEntity: DynamicEntityCommons
-// ) = {
-// for {
-// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity(
-// dynamicEntity,
-// cc.callContext
-// )
-// // granted the CRUD roles to the loggedIn User
-// curdRoles = List(
-// DynamicEntityInfo
-// .canCreateRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo
-// .canUpdateRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo.canGetRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo.canDeleteRole(
-// result.entityName,
-// dynamicEntity.bankId
-// )
-// )
-// } yield {
-// curdRoles.map(role =>
-// Entitlement.entitlement.vend.addEntitlement(
-// dynamicEntity.bankId.getOrElse(""),
-// cc.userId,
-// role.toString()
-// )
-// )
-// val commonsData: DynamicEntityCommons = result
-// (commonsData.jValue, HttpCode.`201`(cc.callContext))
-// }
-// }
-//
-// private def createDynamicEntityDoc = ResourceDoc(
-// createSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(createSystemDynamicEntity),
-// "POST",
-// "/management/system-dynamic-entities",
-// "Create System Level Dynamic Entity",
-// s"""Create a system level Dynamic Entity.
-// |
-// |Note: To see DynamicEntity in API Explorer II, find OBPdynamic-entity or similar in the list of API versions.
-// |
-// |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints.
-// |
-// |**Discovering the generated endpoints:**
-// |
-// |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use:
-// |
-// |`GET /resource-docs/API_VERSION/obp?content=dynamic`
-// |
-// |This returns documentation for all dynamic endpoints including paths, schemas, and required roles.
-// |
-// |For more information about Dynamic Entities see ${Glossary
-// .getGlossaryItemLink("Dynamic-Entities")}
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically
-// |
-// |The following field types are as supported:
-// |${DynamicEntityFieldType.values
-// .map(_.toString)
-// .mkString("[", ", ", ", reference]")}
-// |
-// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat}
-// |
-// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation.
-// |
-// |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity.
-// |
-// |To see the complete list of available reference types and their correct formats, call:
-// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types**
-// |
-// |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format.
-// |
-// |**The hasPersonalEntity flag:**
-// |
-// |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints.
-// |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records.
-// |
-// |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences.
-// |
-// |$dynamicEntityNamingExplanation
-// |
-// |**Example Request Body 1:**
-// |```json
-// |{
-// | "AgentConversation": {
-// | "description": "Stores conversation metadata between users and agents",
-// | "required": ["conversation_id", "user_id"],
-// | "properties": {
-// | "conversation_id": {
-// | "type": "string",
-// | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1"
-// | },
-// | "user_id": {
-// | "type": "string",
-// | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a"
-// | },
-// | "title": {
-// | "type": "string",
-// | "example": "Stripe price ID error"
-// | },
-// | "created_at": {
-// | "type": "string",
-// | "example": "2025-01-07T14:30:00.000Z"
-// | },
-// | "model": {
-// | "type": "string",
-// | "example": "gpt-5"
-// | },
-// | "language": {
-// | "type": "string",
-// | "example": "en"
-// | },
-// | "metadata_platform": {
-// | "type": "string",
-// | "example": "web"
-// | },
-// | "metadata_browser": {
-// | "type": "string",
-// | "example": "Firefox 144.0"
-// | },
-// | "metadata_os": {
-// | "type": "string",
-// | "example": "Ubuntu 22.04"
-// | },
-// | "tags": {
-// | "type": "string",
-// | "example": "stripe,api,error"
-// | },
-// | "summary": {
-// | "type": "string",
-// | "example": "User received 'No such price' error using Stripe API"
-// | },
-// | "custom_metadata": {
-// | "type": "json",
-// | "example": {
-// | "priority": "high",
-// | "tags": ["support", "billing"],
-// | "context": {
-// | "page": "checkout",
-// | "step": 3
-// | }
-// | }
-// | }
-// | }
-// | },
-// | "hasPersonalEntity": true
-// |}
-// |```
-// |
-// |
-// |**Example 2: AgentMessage Entity with Reference to the above Entity**
-// |```json
-// |{
-// | "hasPersonalEntity": true,
-// | "AgentMessage": {
-// | "description": "Stores individual messages within agent conversations",
-// | "required": [
-// | "message_id",
-// | "conversation_id",
-// | "role"
-// | ],
-// | "properties": {
-// | "message_id": {
-// | "type": "string",
-// | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002"
-// | },
-// | "conversation_id": {
-// | "type": "reference:AgentConversation",
-// | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388"
-// | },
-// | "role": {
-// | "type": "string",
-// | "example": "user"
-// | },
-// | "content_text": {
-// | "type": "string",
-// | "example": "I'm using Stripe for the first time and getting an error..."
-// | },
-// | "timestamp": {
-// | "type": "string",
-// | "example": "2025-01-07T14:30:15.000Z"
-// | },
-// | "token_count": {
-// | "type": "integer",
-// | "example": 150
-// | },
-// | "model_used": {
-// | "type": "string",
-// | "example": "gpt-5"
-// | }
-// | }
-// | }
-// |}
-// |```
-// |
-// |$dynamicEntityImportantNotes
-// |
-// |$dynamicEntityGeneratedTags
-// |
-// |$dynamicEntityPianoExample
-// |
-// |**WRONG (will fail validation):**
-// |```json
-// |{
-// | "entity": {
-// | "AgentConversation": { ... }
-// | }
-// |}
-// |```
-// |
-// |**CORRECT:**
-// |```json
-// |{
-// | "AgentConversation": { ... },
-// | "hasPersonalEntity": true
-// |}
-// |```
-// |""",
-// dynamicEntityRequestBodyExample.copy(bankId = None),
-// dynamicEntityResponseBodyExample.copy(bankId = None),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canCreateSystemLevelDynamicEntity))
-// )
-//
-// lazy val createSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val dynamicEntity = DynamicEntityCommons(
-// json.asInstanceOf[JObject],
-// None,
-// cc.userId,
-// None
-// )
-// createDynamicEntityMethod(cc, dynamicEntity)
-// }
-// }
-//
-// private def createBankLevelDynamicEntityDoc = ResourceDoc(
-// createBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(createBankLevelDynamicEntity),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-entities",
-// "Create Bank Level Dynamic Entity",
-// s"""Create a Bank Level DynamicEntity.
-// |
-// |Note: Once you have created a DynamicEntity to see it in the API Explorer II, find OBPdynamic-entity or similar in the list of API versions.
-// |
-// |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints.
-// |
-// |**Discovering the generated endpoints:**
-// |
-// |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use:
-// |
-// |`GET /resource-docs/API_VERSION/obp?content=dynamic`
-// |
-// |This returns documentation for all dynamic endpoints including paths, schemas, and required roles.
-// |
-// |For more information about Dynamic Entities see ${Glossary
-// .getGlossaryItemLink("Dynamic-Entities")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically
-// |
-// |The following field types are as supported:
-// |${DynamicEntityFieldType.values
-// .map(_.toString)
-// .mkString("[", ", ", ", reference]")}
-// |
-// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat}
-// |
-// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation.
-// |
-// |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity.
-// |
-// |To see the complete list of available reference types and their correct formats, call:
-// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types**
-// |
-// |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format.
-// |
-// |**The hasPersonalEntity flag:**
-// |
-// |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints.
-// |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records.
-// |
-// |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences.
-// |
-// |$dynamicEntityNamingExplanation
-// |
-// |**Example Request Body 1:**
-// |```json
-// |{
-// | "AgentConversation": {
-// | "description": "Stores conversation metadata between users and agents",
-// | "required": ["conversation_id", "user_id"],
-// | "properties": {
-// | "conversation_id": {
-// | "type": "string",
-// | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1"
-// | },
-// | "user_id": {
-// | "type": "string",
-// | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a"
-// | },
-// | "title": {
-// | "type": "string",
-// | "example": "Stripe price ID error"
-// | },
-// | "created_at": {
-// | "type": "string",
-// | "example": "2025-01-07T14:30:00.000Z"
-// | },
-// | "model": {
-// | "type": "string",
-// | "example": "gpt-5"
-// | },
-// | "language": {
-// | "type": "string",
-// | "example": "en"
-// | },
-// | "metadata_platform": {
-// | "type": "string",
-// | "example": "web"
-// | },
-// | "metadata_browser": {
-// | "type": "string",
-// | "example": "Firefox 144.0"
-// | },
-// | "metadata_os": {
-// | "type": "string",
-// | "example": "Ubuntu 22.04"
-// | },
-// | "tags": {
-// | "type": "string",
-// | "example": "stripe,api,error"
-// | },
-// | "summary": {
-// | "type": "string",
-// | "example": "User received 'No such price' error using Stripe API"
-// | },
-// | "custom_metadata": {
-// | "type": "json",
-// | "example": {
-// | "priority": "high",
-// | "tags": ["support", "billing"],
-// | "context": {
-// | "page": "checkout",
-// | "step": 3
-// | }
-// | }
-// | }
-// | }
-// | },
-// | "hasPersonalEntity": true
-// |}
-// |```
-// |
-// |
-// |**Example 2: AgentMessage Entity with Reference to the above Entity**
-// |```json
-// |{
-// | "hasPersonalEntity": true,
-// | "AgentMessage": {
-// | "description": "Stores individual messages within agent conversations",
-// | "required": [
-// | "message_id",
-// | "conversation_id",
-// | "role"
-// | ],
-// | "properties": {
-// | "message_id": {
-// | "type": "string",
-// | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002"
-// | },
-// | "conversation_id": {
-// | "type": "reference:AgentConversation",
-// | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388"
-// | },
-// | "role": {
-// | "type": "string",
-// | "example": "user"
-// | },
-// | "content_text": {
-// | "type": "string",
-// | "example": "I'm using Stripe for the first time and getting an error..."
-// | },
-// | "timestamp": {
-// | "type": "string",
-// | "example": "2025-01-07T14:30:15.000Z"
-// | },
-// | "token_count": {
-// | "type": "integer",
-// | "example": 150
-// | },
-// | "model_used": {
-// | "type": "string",
-// | "example": "gpt-5"
-// | }
-// | }
-// | }
-// |}
-// |```
-// |
-// |$dynamicEntityImportantNotes
-// |
-// |$dynamicEntityGeneratedTags
-// |
-// |$dynamicEntityPianoExample
-// |
-// |**WRONG (will fail validation):**
-// |```json
-// |{
-// | "entity": {
-// | "AgentConversation": { ... }
-// | }
-// |}
-// |```
-// |
-// |**CORRECT:**
-// |```json
-// |{
-// | "AgentConversation": { ... },
-// | "hasPersonalEntity": true
-// |}
-// |```
-// |""",
-// dynamicEntityRequestBodyExample.copy(bankId = None),
-// dynamicEntityResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canCreateBankLevelDynamicEntity, canCreateAnyBankLevelDynamicEntity))
-// )
-// lazy val createBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(
-// bankId
-// ) :: "dynamic-entities" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val dynamicEntity = DynamicEntityCommons(
-// json.asInstanceOf[JObject],
-// None,
-// cc.userId,
-// Some(bankId.value)
-// )
-// createDynamicEntityMethod(cc, dynamicEntity)
-// }
-// }
-//
-// // bankId is option, if it is bankLevelEntity, we need BankId, if system Level Entity, bankId is None.
-// private def updateDynamicEntityMethod(
-// bankId: Option[String],
-// dynamicEntityId: String,
-// json: JValue,
-// cc: CallContext
-// ) = {
-// for {
-// // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity.
-// (entity, _) <- NewStyle.function.getDynamicEntityById(
-// bankId,
-// dynamicEntityId,
-// cc.callContext
-// )
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// entity.entityName,
-// None,
-// None,
-// entity.bankId,
-// None,
-// None,
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// entity.entityName
-// )
-// _ <- Helper.booleanToFuture(
-// DynamicEntityOperationNotAllowed,
-// cc = cc.callContext
-// ) {
-// resultList.arr.isEmpty
-// }
-//
-// jsonObject = json.asInstanceOf[JObject]
-// dynamicEntity = DynamicEntityCommons(
-// jsonObject,
-// Some(dynamicEntityId),
-// cc.userId,
-// bankId
-// )
-// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity(
-// dynamicEntity,
-// cc.callContext
-// )
-// } yield {
-// val commonsData: DynamicEntityCommons = result
-// (commonsData.jValue, HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-// private def updateDynamicEntityDoc = ResourceDoc(
-// updateSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateSystemDynamicEntity),
-// "PUT",
-// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update System Level Dynamic Entity",
-// s"""Update a System Level Dynamic Entity.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed.
-// |
-// |The following field types are as supported:
-// |${DynamicEntityFieldType.values
-// .map(_.toString)
-// .mkString("[", ", ", ", reference]")}
-// |
-// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat}
-// |
-// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation.
-// |
-// |To see all available reference types and their correct formats, call:
-// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types**
-// |""",
-// dynamicEntityRequestBodyExample.copy(bankId = None),
-// dynamicEntityResponseBodyExample.copy(bankId = None),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEntityNotFoundByDynamicEntityId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canUpdateSystemDynamicEntity))
-// )
-// lazy val updateSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateDynamicEntityMethod(None, dynamicEntityId, json, cc)
-// }
-// }
-//
-// private def updateBankLevelDynamicEntityDoc = ResourceDoc(
-// updateBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateBankLevelDynamicEntity),
-// "PUT",
-// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update Bank Level Dynamic Entity",
-// s"""Update a Bank Level DynamicEntity.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed.
-// |
-// |The following field types are as supported:
-// |${DynamicEntityFieldType.values
-// .map(_.toString)
-// .mkString("[", ", ", ", reference]")}
-// |
-// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat}
-// |
-// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation.
-// |
-// |To see all available reference types and their correct formats, call:
-// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types**
-// |""",
-// dynamicEntityRequestBodyExample.copy(bankId = None),
-// dynamicEntityResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canUpdateBankLevelDynamicEntity))
-// )
-// lazy val updateBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateDynamicEntityMethod(Some(bankId), dynamicEntityId, json, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(deleteSystemDynamicEntity),
-// "DELETE",
-// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Delete System Level Dynamic Entity",
-// s"""Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}/
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canDeleteSystemLevelDynamicEntity))
-// )
-// lazy val deleteSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteDynamicEntityMethod(None, dynamicEntityId, cc)
-// }
-// }
-//
-//
-//
-// private def deleteDynamicEntityMethod(
-// bankId: Option[String],
-// dynamicEntityId: String,
-// cc: CallContext
-// ) = {
-// for {
-// // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity.
-// (entity, _) <- NewStyle.function.getDynamicEntityById(
-// bankId,
-// dynamicEntityId,
-// cc.callContext
-// )
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// entity.entityName,
-// None,
-// None,
-// entity.bankId,
-// None,
-// None,
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// entity.entityName
-// )
-// _ <- Helper.booleanToFuture(
-// DynamicEntityOperationNotAllowed,
-// cc = cc.callContext
-// ) {
-// resultList.arr.isEmpty
-// }
-// deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity(
-// bankId,
-// dynamicEntityId
-// )
-// } yield {
-// (deleted, HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelDynamicEntity),
-// "DELETE",
-// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Delete Bank Level Dynamic Entity",
-// s"""Delete a Bank Level DynamicEntity specified by DYNAMIC_ENTITY_ID.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}/
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canDeleteBankLevelDynamicEntity))
-// )
-// lazy val deleteBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteDynamicEntityMethod(Some(bankId), dynamicEntityId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getMyDynamicEntities),
-// "GET",
-// "/my/dynamic-entities",
-// "Get My Dynamic Entities",
-// s"""Get all my Dynamic Entities (definitions I created).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "My-Dynamic-Entities"
-// )}""",
-// EmptyBody,
-// ListResult(
-// "dynamic_entities",
-// List(dynamicEntityResponseBodyExample)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi)
-// )
-//
-// lazy val getMyDynamicEntities: OBPEndpoint = {
-// case "my" :: "dynamic-entities" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntitiesByUserId(cc.userId)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities
-// val jObjects = listCommons.map(_.jValue)
-// (
-// ListResult("dynamic_entities", jObjects),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// private def updateMyDynamicEntityDoc = ResourceDoc(
-// updateMyDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateMyDynamicEntity),
-// "PUT",
-// "/my/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update My Dynamic Entity",
-// s"""Update my DynamicEntity.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "My-Dynamic-Entities"
-// )}/
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Update one of my DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed.
-// |
-// |Current support filed types as follow:
-// |${DynamicEntityFieldType.values
-// .map(_.toString)
-// .mkString("[", ", ", ", reference]")}
-// |
-// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat}
-// |
-// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation.
-// |
-// |To see all available reference types and their correct formats, call:
-// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types**
-// |""",
-// dynamicEntityRequestBodyExample.copy(bankId = None),
-// dynamicEntityResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// DynamicEntityNotFoundByDynamicEntityId,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi)
-// )
-//
-// lazy val updateMyDynamicEntity: OBPEndpoint = {
-// case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntitiesByUserId(cc.userId)
-// )
-// entityOption = dynamicEntities.find(
-// _.dynamicEntityId.equals(Some(dynamicEntityId))
-// )
-// myEntity <- NewStyle.function.tryons(
-// InvalidMyDynamicEntityUser,
-// 400,
-// cc.callContext
-// ) {
-// entityOption.get
-// }
-// // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity.
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// myEntity.entityName,
-// None,
-// myEntity.dynamicEntityId,
-// myEntity.bankId,
-// None,
-// Some(myEntity.userId),
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// myEntity.entityName
-// )
-// _ <- Helper.booleanToFuture(
-// DynamicEntityOperationNotAllowed,
-// cc = cc.callContext
-// ) {
-// resultList.arr.isEmpty
-// }
-// jsonObject = json.asInstanceOf[JObject]
-// dynamicEntity = DynamicEntityCommons(
-// jsonObject,
-// Some(dynamicEntityId),
-// cc.userId,
-// myEntity.bankId
-// )
-// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity(
-// dynamicEntity,
-// cc.callContext
-// )
-// } yield {
-// val commonsData: DynamicEntityCommons = result
-// (commonsData.jValue, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyDynamicEntity,
-// implementedInApiVersion,
-// nameOf(deleteMyDynamicEntity),
-// "DELETE",
-// "/my/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Delete My Dynamic Entity",
-// s"""Delete my DynamicEntity specified by DYNAMIC_ENTITY_ID.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "My-Dynamic-Entities"
-// )}
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi)
-// )
-//
-// lazy val deleteMyDynamicEntity: OBPEndpoint = {
-// case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntitiesByUserId(cc.userId)
-// )
-// entityOption = dynamicEntities.find(
-// _.dynamicEntityId.equals(Some(dynamicEntityId))
-// )
-// myEntity <- NewStyle.function.tryons(
-// InvalidMyDynamicEntityUser,
-// 400,
-// cc.callContext
-// ) {
-// entityOption.get
-// }
-// // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity.
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// myEntity.entityName,
-// None,
-// myEntity.dynamicEntityId,
-// myEntity.bankId,
-// None,
-// Some(myEntity.userId),
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// myEntity.entityName
-// )
-// _ <- Helper.booleanToFuture(
-// DynamicEntityOperationNotAllowed,
-// cc = cc.callContext
-// ) {
-// resultList.arr.isEmpty
-// }
-// deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity(
-// myEntity.bankId,
-// dynamicEntityId
-// )
-// } yield {
-// (deleted, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// private def unboxResult[T: Manifest](box: Box[T], entityName: String): T = {
-// if (box.isInstanceOf[Failure]) {
-// val failure = box.asInstanceOf[Failure]
-// // change the internal db column name 'dynamicdataid' to entity's id name
-// val msg = failure.msg.replace(
-// DynamicData.DynamicDataId.dbColumnName,
-// StringUtils.uncapitalize(entityName) + "Id"
-// )
-// val changedMsgFailure = failure.copy(msg = s"$InternalServerError $msg")
-// fullBoxOrException[T](changedMsgFailure)
-// }
-//
-// box.openOrThrowException("impossible error")
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// resetPasswordUrl,
-// implementedInApiVersion,
-// nameOf(resetPasswordUrl),
-// "POST",
-// "/management/user/reset-password-url",
-// "Create password reset url",
-// s"""Create password reset url.
-// |
-// |""",
-// PostResetPasswordUrlJsonV400(
-// "jobloggs",
-// "jo@gmail.com",
-// "74a8ebcc-10e4-4036-bef3-9835922246bf"
-// ),
-// ResetPasswordUrlJsonV400(
-// "https://apisandbox.openbankproject.com/user_mgt/reset_password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canCreateResetPasswordUrl))
-// )
-//
-// lazy val resetPasswordUrl: OBPEndpoint = {
-// case "management" :: "user" :: "reset-password-url" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Helper.booleanToFuture(
-// failMsg = ErrorMessages.NotAllowedEndpoint,
-// cc = cc.callContext
-// ) {
-// APIUtil.getPropsAsBoolValue("ResetPasswordUrlEnabled", false)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordUrlJsonV400]} "
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostResetPasswordUrlJsonV400]
-// }
-// } yield {
-// val resetLink = AuthUser.passwordResetUrl(
-// postedData.username,
-// postedData.email,
-// postedData.user_id
-// )
-// (
-// ResetPasswordUrlJsonV400(resetLink),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// addAccount,
-// implementedInApiVersion,
-// nameOf(addAccount),
-// "POST",
-// "/banks/BANK_ID/accounts",
-// "Create Account (POST)",
-// """Create Account at bank specified by BANK_ID.
-// |
-// |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.
-// |
-// |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.
-// |
-// |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User.
-// |
-// |The 'product_code' field SHOULD be a product_code from Product.
-// |If the product_code matches a product_code from Product, account attributes will be created that match the Product Attributes.
-// |
-// |Note: The Amount MUST be zero.""".stripMargin,
-// createAccountRequestJsonV310,
-// createAccountResponseJsonV310,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidAccountBalanceAmount,
-// InvalidAccountInitialBalance,
-// InitialBalanceMustBeZero,
-// InvalidAccountBalanceCurrency,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canCreateAccount))
-// ).disableAutoValidateRoles() // this means disabled auto roles validation, will manually do the roles validation .
-//
-// lazy val addAccount: OBPEndpoint = {
-// // Create a new account
-// case "banks" :: BankId(
-// bankId
-// ) :: "accounts" :: Nil JsonPost json -> _ => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} "
-// for {
-// createAccountJson <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[CreateAccountRequestJsonV310]
-// }
-// loggedInUserId = cc.userId
-// userIdAccountOwner =
-// if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id
-// else loggedInUserId
-// (postedOrLoggedInUser, callContext) <- NewStyle.function
-// .findByUserId(userIdAccountOwner, cc.callContext)
-//
-// _ <-
-// if (userIdAccountOwner == loggedInUserId)
-// Future.successful(Full(Unit))
-// else
-// NewStyle.function.hasEntitlement(
-// bankId.value,
-// loggedInUserId,
-// canCreateAccount,
-// callContext,
-// s"${UserHasMissingRoles} $canCreateAccount or create account for self"
-// )
-//
-// initialBalanceAsString = createAccountJson.balance.amount
-// // Note: here we map the product_code to account_type
-// accountType = createAccountJson.product_code
-// accountLabel = createAccountJson.label
-// initialBalanceAsNumber <- NewStyle.function.tryons(
-// InvalidAccountInitialBalance,
-// 400,
-// callContext
-// ) {
-// BigDecimal(initialBalanceAsString)
-// }
-// _ <- Helper.booleanToFuture(
-// InitialBalanceMustBeZero,
-// cc = callContext
-// ) { 0 == initialBalanceAsNumber }
-// _ <- Helper.booleanToFuture(
-// InvalidISOCurrencyCode,
-// cc = callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(createAccountJson.balance.currency)
-// }
-// currency = createAccountJson.balance.currency
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(
-// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme",
-// cc = callContext
-// ) {
-// createAccountJson.account_routings
-// .map(_.scheme)
-// .distinct
-// .size == createAccountJson.account_routings.size
-// }
-// alreadyExistAccountRoutings <- Future.sequence(
-// createAccountJson.account_routings.map(accountRouting =>
-// NewStyle.function
-// .getAccountRouting(
-// Some(bankId),
-// accountRouting.scheme,
-// accountRouting.address,
-// callContext
-// )
-// .map(_ => Some(accountRouting))
-// .fallbackTo(Future.successful(None))
-// )
-// )
-// alreadyExistingAccountRouting = alreadyExistAccountRoutings
-// .collect { case Some(accountRouting) =>
-// s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
-// }
-// _ <- Helper.booleanToFuture(
-// s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})",
-// cc = callContext
-// ) {
-// alreadyExistingAccountRouting.isEmpty
-// }
-// (bankAccount, callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// AccountId(APIUtil.generateUUID()),
-// accountType,
-// accountLabel,
-// currency,
-// initialBalanceAsNumber,
-// postedOrLoggedInUser.name,
-// createAccountJson.branch_id,
-// createAccountJson.account_routings.map(r =>
-// AccountRouting(r.scheme, r.address)
-// ),
-// callContext
-// )
-// accountId = bankAccount.accountId
-// (productAttributes, callContext) <- NewStyle.function
-// .getProductAttributesByBankAndCode(
-// bankId,
-// ProductCode(accountType),
-// callContext
-// )
-// (accountAttributes, callContext) <- NewStyle.function
-// .createAccountAttributes(
-// bankId,
-// accountId,
-// ProductCode(accountType),
-// productAttributes,
-// None,
-// callContext: Option[CallContext]
-// )
-// // 1 Create or Update the `Owner` for the new account
-// // 2 Add permission to the user
-// // 3 Set the user as the account holder
-// _ <- BankAccountCreation
-// .setAccountHolderAndRefreshUserAccountAccess(
-// bankId,
-// accountId,
-// postedOrLoggedInUser,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory310.createAccountJSON(
-// userIdAccountOwner,
-// bankAccount,
-// accountAttributes
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// root,
-// implementedInApiVersion,
-// "root",
-// "GET",
-// "/root",
-// "Get API Info (root)",
-// """Returns information about:
-// |
-// |* API version
-// |* Hosted by information
-// |* Hosted at information
-// |* Energy source information
-// |* Git Commit""",
-// EmptyBody,
-// apiInfoJson400,
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil
-// )
-//
-// lazy val root: OBPEndpoint = {
-// case (Nil | "root" :: Nil) JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (
-// JSONFactory400.getApiInfoJSON(
-// OBPAPI4_0_0.version,
-// OBPAPI4_0_0.versionStatus
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCallContext,
-// implementedInApiVersion,
-// nameOf(getCallContext),
-// "GET",
-// "/development/call_context",
-// "Get the Call Context of a current call",
-// s"""Get the Call Context of the current call.
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagApi),
-// Some(List(canGetCallContext))
-// )
-//
-// lazy val getCallContext: OBPEndpoint = {
-// case "development" :: "call_context" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (cc.callContext, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// verifyRequestSignResponse,
-// implementedInApiVersion,
-// nameOf(verifyRequestSignResponse),
-// "GET",
-// "/development/echo/jws-verified-request-jws-signed-response",
-// "Verify Request and Sign Response of a current call",
-// s"""Verify Request and Sign Response of a current call.
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagApi),
-// Some(Nil)
-// )
-//
-// lazy val verifyRequestSignResponse: OBPEndpoint = {
-// case "development" :: "echo" :: "jws-verified-request-jws-signed-response" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (cc.callContext, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAccountLabel,
-// implementedInApiVersion,
-// "updateAccountLabel",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID",
-// "Update Account Label",
-// s"""Update the label for the account. The label is how the account is known to the account owner e.g. 'My savings account'
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// updateAccountJsonV400,
-// successMessage,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError,
-// $BankAccountNotFound,
-// "user does not have access to owner view on account"
-// ),
-// List(apiTagAccount)
-// )
-//
-// lazy val updateAccountLabel: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), account, callContext) <- SS.userAccount
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $InvalidJsonFormat "
-// json <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[UpdateAccountJsonV400]
-// }
-// anyViewContainsCanUpdateBankAccountLabelPermission = Views.views.vend
-// .permission(BankIdAccountId(account.bankId, account.accountId), u)
-// .map(
-// _.views.map(
-// _.allowed_actions.exists(_ == CAN_UPDATE_BANK_ACCOUNT_LABEL)
-// )
-// )
-// .getOrElse(Nil)
-// .find(_.==(true))
-// .getOrElse(false)
-// _ <- Helper.booleanToFuture(
-// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_UPDATE_BANK_ACCOUNT_LABEL)}` permission on any your views",
-// cc = callContext
-// ) {
-// anyViewContainsCanUpdateBankAccountLabelPermission
-// }
-// (success, callContext) <- Connector.connector.vend.updateAccountLabel(
-// bankId,
-// accountId,
-// json.label,
-// callContext
-// ) map { i =>
-// (
-// unboxFullOrFail(
-// i._1,
-// i._2,
-// s"$UpdateBankAccountLabelError Current BankId is $bankId and Current AccountId is $accountId",
-// 404
-// ),
-// i._2
-// )
-// }
-// } yield {
-// (Extraction.decompose(successMessage), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// lockUser,
-// implementedInApiVersion,
-// nameOf(lockUser),
-// "POST",
-// "/users/USERNAME/locks",
-// "Lock the user",
-// s"""
-// |Lock a User.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// userLockStatusJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByProviderAndUsername,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canLockUser))
-// )
-//
-// lazy val lockUser: OBPEndpoint = {
-// case "users" :: username :: "locks" :: Nil JsonPost req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// userLocks <- Future {
-// UserLocksProvider.lockUser(localIdentityProvider, username)
-// } map {
-// unboxFullOrFail(
-// _,
-// callContext,
-// s"$UserNotFoundByProviderAndUsername($username)",
-// 404
-// )
-// }
-// } yield {
-// (
-// JSONFactory400.createUserLockStatusJson(userLocks),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// createUserWithRoles,
-// implementedInApiVersion,
-// nameOf(createUserWithRoles),
-// "POST",
-// "/user-entitlements",
-// "Create (DAuth) User with Roles",
-// s"""
-// |This endpoint is used as part of the DAuth solution to grant Entitlements for Roles to a smart contract on the blockchain.
-// |
-// |Put the smart contract address in username
-// |
-// |For provider use "dauth"
-// |
-// |This endpoint will create the User with username and provider if the User does not already exist.
-// |
-// |Then it will create Entitlements i.e. grant Roles to the User.
-// |
-// |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views)
-// |
-// |i.e. Entitlements are used to create / consume system or bank level resources where as views / account access are used to consume / create customer level resources.
-// |
-// |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":""
-// |
-// |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id"
-// |
-// |Note: The Roles actually granted will depend on the Roles that the calling user has.
-// |
-// |If you try to grant Entitlements to a user that already exist (duplicate entitilements) you will get an error.
-// |
-// |For information about DAuth see below:
-// |
-// |${getGlossaryItem("DAuth")}
-// |
-// |""",
-// postCreateUserWithRolesJsonV400,
-// entitlementsJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// IncorrectRoleName,
-// EntitlementIsBankRole,
-// EntitlementIsSystemRole,
-// EntitlementAlreadyExists,
-// InvalidUserProvider,
-// UnknownError
-// ),
-// List(apiTagRole, apiTagEntitlement, apiTagUser, apiTagDAuth)
-// )
-//
-// lazy val createUserWithRoles: OBPEndpoint = {
-// case "user-entitlements" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(loggedInUser), callContext) <- authenticatedAccess(cc)
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostCreateUserWithRolesJsonV400 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCreateUserWithRolesJsonV400]
-// }
-//
-// // provider must start with dauth., can not create other provider users.
-// _ <- Helper.booleanToFuture(
-// s"$InvalidUserProvider The user.provider must be start with 'dauth.'",
-// cc = Some(cc)
-// ) {
-// postedData.provider.startsWith("dauth.")
-// }
-//
-// // check the system role bankId is Empty, but bank level role need bankId
-// _ <- checkRoleBankIdMappings(callContext, postedData)
-//
-// _ <- checkRolesBankIdExsiting(callContext, postedData)
-//
-// _ <- checkRolesName(callContext, postedData)
-//
-// canCreateEntitlementAtAnyBankRole = Entitlement.entitlement.vend
-// .getEntitlement(
-// "",
-// loggedInUser.userId,
-// canCreateEntitlementAtAnyBank.toString()
-// )
-//
-// (targetUser, callContext) <- NewStyle.function
-// .getOrCreateResourceUser(
-// postedData.provider,
-// postedData.username,
-// callContext
-// )
-//
-// _ <-
-// if (canCreateEntitlementAtAnyBankRole.isDefined) {
-// // If the loggedIn User has `CanCreateEntitlementAtAnyBankRole` role, then we can grant all the requestRoles to the requestUser.
-// // But we must check if the requestUser already has the requestRoles or not.
-// assertTargetUserLacksRoles(
-// targetUser.userId,
-// postedData.roles,
-// callContext
-// )
-// } else {
-// // If the loggedIn user does not have the `CanCreateEntitlementAtAnyBankRole` role, we can only grant the roles which the loggedIn user have.
-// // So we need to check if the requestRoles are beyond the current loggedIn user has.
-// assertUserCanGrantRoles(
-// loggedInUser.userId,
-// postedData.roles,
-// callContext
-// )
-// }
-//
-// addedEntitlements <- addEntitlementsToUser(
-// targetUser.userId,
-// postedData,
-// callContext
-// )
-//
-// } yield {
-// (
-// JSONFactory400.createEntitlementJSONs(addedEntitlements),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getEntitlements,
-// implementedInApiVersion,
-// "getEntitlements",
-// "GET",
-// "/users/USER_ID/entitlements",
-// "Get Entitlements for User",
-// s"""
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// entitlementsJsonV400,
-// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError),
-// List(apiTagRole, apiTagEntitlement, apiTagUser),
-// Some(List(canGetEntitlementsForAnyUserAtAnyBank))
-// )
-//
-// lazy val getEntitlements: OBPEndpoint = {
-// case "users" :: userId :: "entitlements" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// entitlements <- NewStyle.function.getEntitlementsByUserId(
-// userId,
-// cc.callContext
-// )
-// } yield {
-// // Add virtual entitlements for super_admin_user_ids or oidc_operator_user_ids
-// val json = if (isSuperAdmin(userId)) {
-// JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.superAdminVirtualRoles)
-// } else if (isOidcOperator(userId)) {
-// JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.oidcOperatorVirtualRoles)
-// } else {
-// JSONFactory200.createEntitlementJSONs(entitlements)
-// }
-// (json, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getEntitlementsForBank,
-// implementedInApiVersion,
-// nameOf(getEntitlementsForBank),
-// "GET",
-// "/banks/BANK_ID/entitlements",
-// "Get Entitlements for One Bank",
-// s"""
-// |
-// """.stripMargin,
-// EmptyBody,
-// entitlementsJsonV400,
-// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError),
-// List(apiTagRole, apiTagEntitlement, apiTagUser),
-// Some(List(canGetEntitlementsForOneBank, canGetEntitlementsForAnyBank))
-// )
-//
-// val allowedEntitlements =
-// canGetEntitlementsForOneBank :: canGetEntitlementsForAnyBank :: Nil
-// val allowedEntitlementsTxt = allowedEntitlements.mkString(" or ")
-//
-// lazy val getEntitlementsForBank: OBPEndpoint = {
-// case "banks" :: bankId :: "entitlements" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// entitlements <- NewStyle.function.getEntitlementsByBankId(
-// bankId,
-// cc.callContext
-// )
-// } yield {
-// val json = JSONFactory400.createEntitlementJSONs(entitlements)
-// (json, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// addTagForViewOnAccount,
-// implementedInApiVersion,
-// "addTagForViewOnAccount",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags",
-// "Create a tag on account",
-// s"""Posts a tag about an account ACCOUNT_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Authentication is required as the tag is linked with the user.""",
-// postAccountTagJSON,
-// accountTagJSON,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// NoViewPermission,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccountMetadata, apiTagAccount)
-// )
-//
-// lazy val addTagForViewOnAccount: OBPEndpoint = {
-// // add a tag
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(
-// viewId
-// ) :: "metadata" :: "tags" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg = s"$NoViewPermission can_add_tag. Current ViewId($viewId)",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_ADD_TAG)
-// }
-// tagJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostTransactionTagJSON ",
-// 400,
-// callContext
-// ) {
-// json.extract[PostTransactionTagJSON]
-// }
-// (postedTag, callContext) <- Future(
-// Tags.tags.vend.addTagOnAccount(bankId, accountId)(
-// u.userPrimaryKey,
-// viewId,
-// tagJson.value,
-// now
-// )
-// ) map { i =>
-// (connectorEmptyResponse(i, callContext), callContext)
-// }
-// } yield {
-// (
-// JSONFactory400.createAccountTagJSON(postedTag),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteTagForViewOnAccount,
-// implementedInApiVersion,
-// "deleteTagForViewOnAccount",
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags/TAG_ID",
-// "Delete a tag on account",
-// s"""Deletes the tag TAG_ID about the account ACCOUNT_ID made on [view](#1_2_1-getViewsForBankAccount).
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Authentication is required as the tag is linked with the user.""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// NoViewPermission,
-// ViewNotFound,
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccountMetadata, apiTagAccount)
-// )
-//
-// lazy val deleteTagForViewOnAccount: OBPEndpoint = {
-// // delete a tag
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(
-// viewId
-// ) :: "metadata" :: "tags" :: tagId :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$NoViewPermission can_delete_tag. Current ViewId($viewId)",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_DELETE_TAG)
-// }
-// deleted <- Future(
-// Tags.tags.vend.deleteTagOnAccount(bankId, accountId)(tagId)
-// ) map { i =>
-// (connectorEmptyResponse(i, callContext), callContext)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTagsForViewOnAccount,
-// implementedInApiVersion,
-// "getTagsForViewOnAccount",
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags",
-// "Get tags on account",
-// s"""Returns the account ACCOUNT_ID tags made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).
-// |${userAuthenticationMessage(true)}
-// |
-// |Authentication is required as the tag is linked with the user.""",
-// EmptyBody,
-// accountTagsJSON,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// NoViewPermission,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccountMetadata, apiTagAccount)
-// )
-//
-// lazy val getTagsForViewOnAccount: OBPEndpoint = {
-// // get tags
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "metadata" :: "tags" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$NoViewPermission can_see_tags. Current ViewId($viewId)",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_SEE_TAGS)
-// }
-// tags <- Future(
-// Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId)
-// )
-// } yield {
-// val json = JSONFactory400.createAccountTagsJSON(tags)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCoreAccountById,
-// implementedInApiVersion,
-// nameOf(getCoreAccountById),
-// "GET",
-// "/my/banks/BANK_ID/accounts/ACCOUNT_ID/account",
-// "Get Account by Id (Core)",
-// s"""Information returned about the account specified by ACCOUNT_ID:
-// |
-// |* Number - The human readable account number given by the bank that identifies the account.
-// |* Label - A label given by the owner of the account
-// |* Owners - Users that own this account
-// |* Type - The type of account
-// |* Balance - Currency and Value
-// |* Account Routings - A list that might include IBAN or national account identifiers
-// |* Account Rules - A list that might include Overdraft and other bank specific rules
-// |* Tags - A list of Tags assigned to this account
-// |
-// |This call returns the owner view and requires access to that view.
-// |
-// |
-// |""".stripMargin,
-// EmptyBody,
-// moderatedCoreAccountJsonV400,
-// List($AuthenticatedUserIsRequired, $BankAccountNotFound, UnknownError),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-// lazy val getCoreAccountById: OBPEndpoint = {
-// // get account by id (assume owner view requested)
-// case "my" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "account" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), account, callContext) <- SS.userAccount
-// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(
-// u,
-// BankIdAccountId(account.bankId, account.accountId),
-// callContext
-// )
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(
-// account,
-// view,
-// user,
-// callContext
-// )
-// } yield {
-// val availableViews: List[View] =
-// Views.views.vend.privateViewsUserCanAccessForAccount(
-// u,
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// (
-// createNewCoreBankAccountJson(moderatedAccount, availableViews),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPrivateAccountByIdFull,
-// implementedInApiVersion,
-// nameOf(getPrivateAccountByIdFull),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account",
-// "Get Account by Id (Full)",
-// """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):
-// |
-// |* Number
-// |* Owners
-// |* Type
-// |* Balance
-// |* IBAN
-// |* Available views (sorted by short_name)
-// |
-// |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).
-// |
-// |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.
-// |This call provides balance and other account information via delegated authentication using OAuth.
-// |
-// |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.
-// |""".stripMargin,
-// EmptyBody,
-// moderatedAccountJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// apiTagAccount :: Nil
-// )
-// lazy val getPrivateAccountByIdFull: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(
-// account,
-// view,
-// user,
-// callContext
-// )
-// (accountAttributes, callContext) <- NewStyle.function
-// .getAccountAttributesByAccount(
-// bankId,
-// accountId,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// val availableViews =
-// Views.views.vend.privateViewsUserCanAccessForAccount(
-// u,
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// val viewsAvailable =
-// availableViews.map(JSONFactory.createViewJSON).sortBy(_.short_name)
-// val tags = Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId)
-// (
-// createBankAccountJSON(
-// moderatedAccount,
-// viewsAvailable,
-// accountAttributes,
-// tags
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountByAccountRouting,
-// implementedInApiVersion,
-// nameOf(getAccountByAccountRouting),
-// "POST",
-// "/management/accounts/account-routing-query",
-// "Get Account by Account Routing",
-// """This endpoint returns the account (if it exists) linked with the provided scheme and address.
-// |
-// |The `bank_id` field is optional, but if it's not provided, we don't guarantee that the returned account is unique across all the banks.
-// |
-// |Example of account routing scheme: `IBAN`, "OBP", "AccountNumber", ...
-// |Example of account routing address: `DE17500105178275645584`, "321774cc-fccd-11ea-adc1-0242ac120002", "55897106215", ...
-// |
-// |""".stripMargin,
-// bankAccountRoutingJson,
-// moderatedAccountJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccount)
-// )
-// lazy val getAccountByAccountRouting: OBPEndpoint = {
-// case "management" :: "accounts" :: "account-routing-query" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121"
-// for {
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[BankAccountRoutingJson]
-// }
-//
-// (account, callContext) <- NewStyle.function.getBankAccountByRouting(
-// postJson.bank_id.map(BankId(_)),
-// postJson.account_routing.scheme,
-// postJson.account_routing.address,
-// cc.callContext
-// )
-//
-// user @ Full(u) = cc.user
-// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(
-// u,
-// BankIdAccountId(account.bankId, account.accountId),
-// callContext
-// )
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(
-// account,
-// view,
-// user,
-// callContext
-// )
-//
-// (accountAttributes, callContext) <- NewStyle.function
-// .getAccountAttributesByAccount(
-// account.bankId,
-// account.accountId,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// val availableViews =
-// Views.views.vend.privateViewsUserCanAccessForAccount(
-// cc.user.openOrThrowException("Exception user"),
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// val viewsAvailable = availableViews
-// .map(JSONFactory.createViewJSON)
-// .sortBy(_.short_name)
-// val tags = Tags.tags.vend
-// .getTagsOnAccount(account.bankId, account.accountId)(view.viewId)
-// (
-// createBankAccountJSON(
-// moderatedAccount,
-// viewsAvailable,
-// accountAttributes,
-// tags
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountsByAccountRoutingRegex,
-// implementedInApiVersion,
-// nameOf(getAccountsByAccountRoutingRegex),
-// "POST",
-// "/management/accounts/account-routing-regex-query",
-// "Get Accounts by Account Routing Regex",
-// """This endpoint returns an array of accounts matching the provided routing scheme and the routing address regex.
-// |
-// |The `bank_id` field is optional.
-// |
-// |Example of account routing scheme: `IBAN`, `OBP`, `AccountNumber`, ...
-// |Example of account routing address regex: `DE175.*`, `55897106215-[A-Z]{3}`, ...
-// |
-// |This endpoint can be used to retrieve multiples accounts matching a same account routing address pattern.
-// |For example, if you want to link multiple accounts having different currencies, you can create an account
-// |with `123456789-EUR` as Account Number and an other account with `123456789-USD` as Account Number.
-// |So we can identify the Account Number as `123456789`, so to get all the accounts with the same account number
-// |and the different currencies, we can use this body in the request :
-// |
-// |```
-// |{
-// | "bank_id": "BANK_ID",
-// | "account_routing": {
-// | "scheme": "AccountNumber",
-// | "address": "123456789-[A-Z]{3}"
-// | }
-// |}
-// |```
-// |
-// |This request will returns the accounts matching the routing address regex (`123456789-EUR` and `123456789-USD`).
-// |
-// |""".stripMargin,
-// bankAccountRoutingJson,
-// moderatedAccountsJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccount)
-// )
-// lazy val getAccountsByAccountRoutingRegex: OBPEndpoint = {
-// case "management" :: "accounts" :: "account-routing-regex-query" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121"
-// for {
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[BankAccountRoutingJson]
-// }
-//
-// (accountRoutings, callContext) <- NewStyle.function
-// .getAccountRoutingsByScheme(
-// postJson.bank_id.map(BankId(_)),
-// postJson.account_routing.scheme,
-// cc.callContext
-// )
-//
-// accountRoutingAddressRegex = postJson.account_routing.address.r
-// filteredAccountRoutings = accountRoutings.filter(accountRouting =>
-// accountRoutingAddressRegex
-// .findFirstIn(accountRouting.accountRouting.address)
-// .isDefined
-// )
-//
-// user @ Full(u) = cc.user
-//
-// accountsJson <- Future.sequence(
-// filteredAccountRoutings.map(accountRouting =>
-// for {
-// (account, callContext) <- NewStyle.function.getBankAccount(
-// accountRouting.bankId,
-// accountRouting.accountId,
-// callContext
-// )
-// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(
-// u,
-// BankIdAccountId(account.bankId, account.accountId),
-// callContext
-// )
-// moderatedAccount <- NewStyle.function
-// .moderatedBankAccountCore(account, view, user, callContext)
-// (accountAttributes, callContext) <- NewStyle.function
-// .getAccountAttributesByAccount(
-// account.bankId,
-// account.accountId,
-// callContext: Option[CallContext]
-// )
-// availableViews = Views.views.vend
-// .privateViewsUserCanAccessForAccount(
-// cc.user.openOrThrowException("Exception user"),
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// viewsAvailable = availableViews
-// .map(JSONFactory.createViewJSON)
-// .sortBy(_.short_name)
-// tags = Tags.tags.vend.getTagsOnAccount(
-// account.bankId,
-// account.accountId
-// )(view.viewId)
-// } yield createBankAccountJSON(
-// moderatedAccount,
-// viewsAvailable,
-// accountAttributes,
-// tags
-// )
-// )
-// )
-// } yield {
-// (
-// ModeratedAccountsJSON400(accountsJson),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountsBalancesForCurrentUser,
-// implementedInApiVersion,
-// nameOf(getBankAccountsBalancesForCurrentUser),
-// "GET",
-// "/banks/BANK_ID/balances",
-// "Get Accounts Balances",
-// """Get the Balances for the Accounts of the current User at one bank.""",
-// EmptyBody,
-// accountBalancesV400Json,
-// List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountsBalancesForCurrentUser: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (allowedAccounts, callContext) <- BalanceNewStyle
-// .getAccountAccessAtBank(u, bankId, callContext)
-// (accountsBalances, callContext) <- BalanceNewStyle
-// .getBankAccountsBalances(allowedAccounts, callContext)
-// } yield {
-// (createBalancesJson(accountsBalances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountBalancesForCurrentUser,
-// implementedInApiVersion,
-// nameOf(getBankAccountBalancesForCurrentUser),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances",
-// "Get Account Balances",
-// """Get the Balances for one Account of the current User at one bank.""",
-// EmptyBody,
-// accountBalanceV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CannotFindAccountAccess,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountBalancesForCurrentUser: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "balances" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (allowedAccounts, callContext) <- BalanceNewStyle
-// .getAccountAccessAtBank(u, bankId, callContext)
-// msg = s"$CannotFindAccountAccess AccountId(${accountId.value})"
-// bankIdAccountId <- NewStyle.function.tryons(
-// msg,
-// 400,
-// cc.callContext
-// ) {
-// allowedAccounts.find(_.accountId == accountId).get
-// }
-// (accountBalances, callContext) <- BalanceNewStyle
-// .getBankAccountBalances(bankIdAccountId, callContext)
-// } yield {
-// (
-// createAccountBalancesJson(accountBalances),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getFirehoseAccountsAtOneBank,
-// implementedInApiVersion,
-// nameOf(getFirehoseAccountsAtOneBank),
-// "GET",
-// "/banks/BANK_ID/firehose/accounts/views/VIEW_ID",
-// "Get Firehose Accounts at Bank",
-// s"""
-// |Get all Accounts at a Bank.
-// |
-// |This endpoint allows bulk access to all accounts at the specified bank.
-// |
-// |Requires the CanUseFirehoseAtAnyBank Role or CanUseAccountFirehose Role
-// |
-// |Returns all accounts at the bank. The VIEW_ID parameter determines what account data fields are visible according to the view's permissions.
-// |
-// |The view specified must have is_firehose = true
-// |
-// |For VIEW_ID try 'owner' or 'firehose'
-// |
-// |Optional request parameters for filtering by account attributes:
-// |URL params example:
-// | /banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1
-// |
-// |To invalidate browser cache, add timestamp query parameter as follows (the parameter name must be `_timestamp_`):
-// |URL params example:
-// | `/banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1&_timestamp_=1596762180358`
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// moderatedFirehoseAccountsJsonV400,
-// List($BankNotFound),
-// List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData),
-// Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))
-// )
-//
-// lazy val getFirehoseAccountsAtOneBank: OBPEndpoint = {
-// // get private accounts for all banks
-// case "banks" :: BankId(
-// bankId
-// ) :: "firehose" :: "accounts" :: "views" :: ViewId(
-// viewId
-// ) :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), bank, callContext) <- SS.userBank
-// _ <- Helper.booleanToFuture(
-// failMsg = AccountFirehoseNotAllowedOnThisInstance,
-// cc = cc.callContext
-// ) {
-// allowAccountFirehose
-// }
-// // here must be a system view, not accountIds in the URL
-// view <- ViewNewStyle.checkViewAccessAndReturnView(
-// viewId,
-// BankIdAccountId(bankId, AccountId("")),
-// Some(u),
-// callContext
-// )
-// availableBankIdAccountIdList <- Future {
-// Views.views.vend
-// .getAllFirehoseAccounts(bank.bankId)
-// .map(a => BankIdAccountId(a.bankId, a.accountId))
-// }
-// params = req.params
-// .filterNot(
-// _._1 == PARAM_TIMESTAMP
-// ) // ignore `_timestamp_` parameter, it is for invalid Browser caching
-// .filterNot(_._1 == PARAM_LOCALE)
-// availableBankIdAccountIdList2 <-
-// if (params.isEmpty) {
-// Future.successful(availableBankIdAccountIdList)
-// } else {
-// AccountAttributeX.accountAttributeProvider.vend
-// .getAccountIdsByParams(bankId, params)
-// .map { boxedAccountIds =>
-// val accountIds = boxedAccountIds.getOrElse(Nil)
-// availableBankIdAccountIdList.filter(
-// availableBankIdAccountId =>
-// accountIds
-// .contains(availableBankIdAccountId.accountId.value)
-// )
-// }
-// }
-// moderatedAccounts: List[ModeratedBankAccount] = for {
-// // Here is a new for-loop to get the moderated accouts for the firehose user, according to the viewId.
-// // 1 each accountId-> find a proper bankAccount object.
-// // 2 each bankAccount object find the proper view.
-// // 3 use view and user to moderate the bankaccount object.
-// bankIdAccountId <- availableBankIdAccountIdList2
-// (bankAccount, callContext) <- Connector.connector.vend
-// .getBankAccountLegacy(
-// bankIdAccountId.bankId,
-// bankIdAccountId.accountId,
-// callContext
-// ) ?~! s"$BankAccountNotFound Current Bank_Id(${bankIdAccountId.bankId}), Account_Id(${bankIdAccountId.accountId}) "
-// moderatedAccount <- bankAccount.moderatedBankAccount(
-// view,
-// bankIdAccountId,
-// Full(u),
-// callContext
-// ) // Error handling is in lower method
-// } yield {
-// moderatedAccount
-// }
-// // if there are accountAttribute query parameter, link to corresponding accountAttributes.
-// (accountAttributes: Option[List[AccountAttribute]], callContext) <-
-// if (moderatedAccounts.nonEmpty && params.nonEmpty) {
-// val futures: List[OBPReturnType[List[AccountAttribute]]] =
-// availableBankIdAccountIdList2.map { bankIdAccount =>
-// val BankIdAccountId(bId, accountId) = bankIdAccount
-// NewStyle.function.getAccountAttributesByAccount(
-// bId,
-// accountId,
-// callContext: Option[CallContext]
-// )
-// }
-// Future.reduceLeft(futures) { (r, t) => // combine to one future
-// r.copy(_1 = t._1 ::: t._1)
-// } map (it =>
-// (Some(it._1), it._2)
-// ) // convert list to Option[List[AccountAttribute]]
-// } else {
-// Future.successful(None, callContext)
-// }
-// } yield {
-// (
-// JSONFactory400.createFirehoseCoreBankAccountJSON(
-// moderatedAccounts,
-// accountAttributes
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getFastFirehoseAccountsAtOneBank,
-// implementedInApiVersion,
-// nameOf(getFastFirehoseAccountsAtOneBank),
-// "GET",
-// "/management/banks/BANK_ID/fast-firehose/accounts",
-// "Get Fast Firehose Accounts at Bank",
-// s"""
-// |
-// |This endpoint allows bulk access to accounts.
-// |
-// |optional pagination parameters for filter with accounts
-// |${urlParametersDocument(true, false)}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// fastFirehoseAccountsJsonV400,
-// List($BankNotFound),
-// List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData),
-// Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))
-// )
-//
-// lazy val getFastFirehoseAccountsAtOneBank: OBPEndpoint = {
-// // get private accounts for all banks
-// case "management" :: "banks" :: BankId(
-// bankId
-// ) :: "fast-firehose" :: "accounts" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), bank, callContext) <- SS.userBank
-// _ <- Helper.booleanToFuture(
-// failMsg = AccountFirehoseNotAllowedOnThisInstance,
-// cc = cc.callContext
-// ) {
-// allowAccountFirehose
-// }
-// allowedParams = List("limit", "offset", "sort_direction")
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- NewStyle.function.createObpParams(
-// httpParams,
-// allowedParams,
-// callContext
-// )
-// (firehoseAccounts, callContext) <- NewStyle.function
-// .getBankAccountsWithAttributes(bankId, obpQueryParams, callContext)
-// } yield {
-// (
-// JSONFactory400.createFirehoseBankAccountJSON(firehoseAccounts),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersByCustomerPhoneNumber,
-// implementedInApiVersion,
-// nameOf(getCustomersByCustomerPhoneNumber),
-// "POST",
-// "/banks/BANK_ID/search/customers/mobile-phone-number",
-// "Get Customers by MOBILE_PHONE_NUMBER",
-// s"""Gets the Customers specified by MOBILE_PHONE_NUMBER.
-// |
-// |There are two wildcards often used in conjunction with the LIKE operator:
-// | % - The percent sign represents zero, one, or multiple characters
-// | _ - The underscore represents a single character
-// |For example {"customer_phone_number":"%381%"} lists all numbers which contain 381 sequence
-// |
-// |""",
-// postCustomerPhoneNumberJsonV400,
-// customerJsonV310,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersByCustomerPhoneNumber: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "search" :: "customers" :: "mobile-phone-number" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostCustomerPhoneNumberJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostCustomerPhoneNumberJsonV400]
-// }
-// (customers, callContext) <- NewStyle.function
-// .getCustomersByCustomerPhoneNumber(
-// bankId,
-// postedData.mobile_phone_number,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory300.createCustomersJson(customers),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCurrentUserId,
-// implementedInApiVersion,
-// nameOf(getCurrentUserId),
-// "GET",
-// "/users/current/user_id",
-// "Get User Id (Current)",
-// s"""Get the USER_ID of the logged in user
-// |
-// |${userAuthenticationMessage(true)}
-// """.stripMargin,
-// EmptyBody,
-// userIdJsonV400,
-// List(AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagUser)
-// )
-//
-// lazy val getCurrentUserId: OBPEndpoint = {
-// case "users" :: "current" :: "user_id" :: Nil JsonGet _ => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// } yield {
-// (
-// JSONFactory400.createUserIdInfoJson(u),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserByUserId,
-// implementedInApiVersion,
-// nameOf(getUserByUserId),
-// "GET",
-// "/users/user_id/USER_ID",
-// "Get User by USER_ID",
-// s"""Get user by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |CanGetAnyUser entitlement is required,
-// |
-// """.stripMargin,
-// EmptyBody,
-// userJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundById,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUserByUserId: OBPEndpoint = {
-// case "users" :: "user_id" :: userId :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// user <- Users.users.vend.getUserByUserIdFuture(userId) map { x =>
-// unboxFullOrFail(
-// x,
-// cc.callContext,
-// s"$UserNotFoundByUserId Current UserId($userId)"
-// )
-// }
-// entitlements <- NewStyle.function.getEntitlementsByUserId(
-// user.userId,
-// cc.callContext
-// )
-// acceptMarketingInfo <- NewStyle.function.getAgreementByUserId(
-// user.userId,
-// "accept_marketing_info",
-// cc.callContext
-// )
-// termsAndConditions <- NewStyle.function.getAgreementByUserId(
-// user.userId,
-// "terms_and_conditions",
-// cc.callContext
-// )
-// privacyConditions <- NewStyle.function.getAgreementByUserId(
-// user.userId,
-// "privacy_conditions",
-// cc.callContext
-// )
-// isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
-// } yield {
-// val agreements =
-// acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList
-// (
-// JSONFactory400.createUserInfoJSON(
-// user,
-// entitlements,
-// Some(agreements),
-// isLocked
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserByUsername,
-// implementedInApiVersion,
-// nameOf(getUserByUsername),
-// "GET",
-// "/users/username/USERNAME",
-// "Get User by USERNAME",
-// s"""Get user by USERNAME
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetAnyUser entitlement is required,
-// |
-// """.stripMargin,
-// EmptyBody,
-// userJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByProviderAndUsername,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUserByUsername: OBPEndpoint = {
-// case "users" :: "username" :: username :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// user <- Users.users.vend.getUserByProviderAndUsernameFuture(
-// Constant.localIdentityProvider,
-// username
-// ) map { x =>
-// unboxFullOrFail(
-// x,
-// cc.callContext,
-// UserNotFoundByProviderAndUsername,
-// 404
-// )
-// }
-// entitlements <- NewStyle.function.getEntitlementsByUserId(
-// user.userId,
-// cc.callContext
-// )
-// isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
-// } yield {
-// (
-// JSONFactory400.createUserInfoJSON(
-// user,
-// entitlements,
-// None,
-// isLocked
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUsersByEmail,
-// implementedInApiVersion,
-// nameOf(getUsersByEmail),
-// "GET",
-// "/users/email/USER_EMAIL/terminator",
-// "Get Users by Email Address",
-// s"""Get users by email address
-// |
-// |${userAuthenticationMessage(true)}
-// |CanGetAnyUser entitlement is required,
-// |
-// """.stripMargin,
-// EmptyBody,
-// usersJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByEmail,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUsersByEmail: OBPEndpoint = {
-// case "users" :: "email" :: email :: "terminator" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// users <- Users.users.vend.getUsersByEmail(email)
-// } yield {
-// (
-// JSONFactory400.createUsersJson(users),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUsers,
-// implementedInApiVersion,
-// nameOf(getUsers),
-// "GET",
-// "/users",
-// "Get all Users",
-// s"""Get all users
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetAnyUser entitlement is required,
-// |
-// |${urlParametersDocument(false, false)}
-// |* locked_status (if null ignore)
-// |
-// """.stripMargin,
-// EmptyBody,
-// usersJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUsers: OBPEndpoint = {
-// case "users" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(
-// httpParams,
-// cc.callContext
-// )
-// users <- Users.users.vend.getUsers(obpQueryParams)
-// } yield {
-// (JSONFactory400.createUsersJson(users), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUserInvitation,
-// implementedInApiVersion,
-// nameOf(createUserInvitation),
-// "POST",
-// "/banks/BANK_ID/user-invitation",
-// "Create User Invitation",
-// s"""Create User Invitation.
-// |
-// | This endpoint will send an invitation email to the developers, then they can use the link to create the obp user.
-// |
-// | purpose filed only support:${UserInvitationPurpose.values
-// .toString()}.
-// |
-// | You can customise the email details use the following webui props:
-// |
-// | when purpose == ${UserInvitationPurpose.DEVELOPER.toString}
-// | webui_developer_user_invitation_email_subject
-// | webui_developer_user_invitation_email_from
-// | webui_developer_user_invitation_email_text
-// | webui_developer_user_invitation_email_html_text
-// |
-// | when purpose = == ${UserInvitationPurpose.CUSTOMER.toString}
-// | webui_customer_user_invitation_email_subject
-// | webui_customer_user_invitation_email_from
-// | webui_customer_user_invitation_email_text
-// | webui_customer_user_invitation_email_html_text
-// |
-// |""",
-// userInvitationPostJsonV400,
-// userInvitationJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagUserInvitation, apiTagKyc),
-// Some(canCreateUserInvitation :: Nil)
-// )
-//
-// lazy val createUserInvitation: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user-invitation" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// logger.debug(s"Hello from the endpoint {$createUserInvitation}")
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostUserInvitationJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostUserInvitationJsonV400]
-// }
-//
-// _ <- NewStyle.function.tryons(
-// s"$InvalidJsonValue postedData.purpose only support ${UserInvitationPurpose.values.toString()}",
-// 400,
-// cc.callContext
-// ) {
-// UserInvitationPurpose.withName(postedData.purpose)
-// }
-//
-// (invitation, callContext) <- NewStyle.function.createUserInvitation(
-// bankId,
-// postedData.first_name,
-// postedData.last_name,
-// postedData.email,
-// postedData.company,
-// postedData.country,
-// postedData.purpose,
-// cc.callContext
-// )
-// } yield {
-// val link =
-// s"${APIUtil.getPropsValue("user_invitation_link_base_URL", APIUtil.getPropsValue("portal_hostname", Constant.HostName))}/user-invitation?id=${invitation.secretKey}"
-// if (postedData.purpose == UserInvitationPurpose.DEVELOPER.toString) {
-// val subject = getWebUiPropsValue(
-// "webui_developer_user_invitation_email_subject",
-// "Welcome to the API Playground"
-// )
-// val from = getWebUiPropsValue(
-// "webui_developer_user_invitation_email_from",
-// "do-not-reply@openbankproject.com"
-// )
-// val customText = getWebUiPropsValue(
-// "webui_developer_user_invitation_email_text",
-// DEFAULT_EMAIL_TEXT
-// )
-// logger.debug(s"customText: ${customText}")
-// val customHtmlText = getWebUiPropsValue(
-// "webui_developer_user_invitation_email_html_text",
-// DEFAULT_EMAIL_HTML
-// )
-// .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName)
-// .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link)
-// logger.debug(s"customHtmlText: ${customHtmlText}")
-// logger.debug(
-// s"Before send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}"
-// )
-//
-// // Use Apache Commons Email wrapper instead of Lift Mailer
-// val emailContent = EmailContent(
-// from = from,
-// to = List(invitation.email),
-// subject = subject,
-// textContent = Some(customText),
-// htmlContent = Some(customHtmlText)
-// )
-//
-// sendHtmlEmail(emailContent) match {
-// case Full(messageId) =>
-// logger.debug(
-// s"Email sent successfully with Message-ID: $messageId"
-// )
-// case Empty => logger.error("Failed to send user invitation email")
-// }
-//
-// logger.debug(
-// s"After send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}"
-// )
-// } else {
-// val subject = getWebUiPropsValue(
-// "webui_customer_user_invitation_email_subject",
-// "Welcome to the API Playground"
-// )
-// val from = getWebUiPropsValue(
-// "webui_customer_user_invitation_email_from",
-// "do-not-reply@openbankproject.com"
-// )
-// val customText = getWebUiPropsValue(
-// "webui_customer_user_invitation_email_text",
-// DEFAULT_EMAIL_TEXT
-// )
-// logger.debug(s"customText: ${customText}")
-// val customHtmlText = getWebUiPropsValue(
-// "webui_customer_user_invitation_email_html_text",
-// DEFAULT_EMAIL_HTML
-// )
-// .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName)
-// .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link)
-// logger.debug(s"customHtmlText: ${customHtmlText}")
-// logger.debug(s"Before send user invitation by email.")
-//
-// // Use Apache Commons Email wrapper instead of Lift Mailer
-// val emailContent = EmailContent(
-// from = from,
-// to = List(invitation.email),
-// subject = subject,
-// textContent = Some(customText),
-// htmlContent = Some(customHtmlText)
-// )
-//
-// sendHtmlEmail(emailContent) match {
-// case Full(messageId) =>
-// logger.debug(
-// s"Email sent successfully with Message-ID: $messageId"
-// )
-// case Empty => logger.error("Failed to send user invitation email")
-// }
-//
-// logger.debug(s"After send user invitation by email.")
-// }
-// (
-// JSONFactory400.createUserInvitationJson(invitation),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserInvitationAnonymous,
-// implementedInApiVersion,
-// nameOf(getUserInvitationAnonymous),
-// "POST",
-// "/banks/BANK_ID/user-invitations",
-// "Get User Invitation Information",
-// s"""Get User Invitation Information.
-// |
-// |${userAuthenticationMessage(false)}
-// |""",
-// PostUserInvitationAnonymousJsonV400(secret_key = 5819479115482092878L),
-// userInvitationJsonV400,
-// List(
-// $BankNotFound,
-// UserCustomerLinksNotFoundForUser,
-// CannotGetUserInvitation,
-// CannotFindUserInvitation,
-// UnknownError
-// ),
-// List(apiTagUserInvitation, apiTagKyc)
-// )
-//
-// lazy val getUserInvitationAnonymous: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user-invitations" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostUserInvitationAnonymousJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostUserInvitationAnonymousJsonV400]
-// }
-// (invitation, callContext) <- NewStyle.function.getUserInvitation(
-// bankId,
-// postedData.secret_key,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// CannotFindUserInvitation,
-// 404,
-// cc.callContext
-// ) {
-// invitation.status == "CREATED"
-// }
-// _ <- Helper.booleanToFuture(
-// CannotFindUserInvitation,
-// 404,
-// cc.callContext
-// ) {
-// val validUntil = Calendar.getInstance
-// validUntil.setTime(invitation.createdAt.get)
-// validUntil.add(Calendar.HOUR, 24)
-// validUntil.getTime.after(new Date())
-// }
-// } yield {
-// (
-// JSONFactory400.createUserInvitationJson(invitation),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserInvitation,
-// implementedInApiVersion,
-// nameOf(getUserInvitation),
-// "GET",
-// "/banks/BANK_ID/user-invitations/SECRET_LINK",
-// "Get User Invitation",
-// s""" Get User Invitation
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userInvitationJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUserInvitation),
-// Some(List(canGetUserInvitation))
-// )
-//
-// lazy val getUserInvitation: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user-invitations" :: secretLink :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (invitation, callContext) <- NewStyle.function.getUserInvitation(
-// bankId,
-// secretLink.toLong,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createUserInvitationJson(invitation),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserInvitations,
-// implementedInApiVersion,
-// nameOf(getUserInvitations),
-// "GET",
-// "/banks/BANK_ID/user-invitations",
-// "Get User Invitations",
-// s""" Get User Invitations
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userInvitationJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUserInvitation),
-// Some(List(canGetUserInvitation))
-// )
-//
-// lazy val getUserInvitations: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "user-invitations" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (invitations, callContext) <- NewStyle.function.getUserInvitations(
-// bankId,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createUserInvitationJson(invitations),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteUser,
-// implementedInApiVersion,
-// nameOf(deleteUser),
-// "DELETE",
-// "/users/USER_ID",
-// "Delete a User",
-// s"""Delete a User.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canDeleteUser))
-// )
-//
-// lazy val deleteUser: OBPEndpoint = {
-// case "users" :: userId :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- NewStyle.function.findByUserId(
-// userId,
-// cc.callContext
-// )
-// (userDeleted, callContext) <- NewStyle.function.deleteUser(
-// user.userPrimaryKey,
-// callContext
-// )
-// } yield {
-// (Full(userDeleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBank,
-// implementedInApiVersion,
-// "createBank",
-// "POST",
-// "/banks",
-// "Create Bank",
-// s"""Create a new bank (Authenticated access).
-// |
-// |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.
-// |Thus the User can manage the bank they create and assign Roles to other Users.
-// |
-// |Only SANDBOX mode (i.e. when connector=mapped in properties file)
-// |The settlement accounts are automatically created by the system when the bank is created.
-// |Name and account id are created in accordance to the next rules:
-// | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)
-// | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)
-// |
-// |""",
-// postBankJson400,
-// bankJson400,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// InsufficientAuthorisationToCreateBank,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canCreateBank))
-// )
-//
-// lazy val createBank: OBPEndpoint = {
-// case "banks" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $BankJson400 "
-// for {
-// bank <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[BankJson400]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = ErrorMessages.InvalidConsumerCredentials,
-// cc = cc.callContext
-// ) {
-// cc.callContext.map(_.consumer.isDefined == true).isDefined
-// }
-//
-// checkShortStringValue = APIUtil.checkShortString(bank.id)
-//
-// _ <- Helper.booleanToFuture(
-// failMsg = s"$checkShortStringValue.",
-// cc = cc.callContext
-// ) {
-// checkShortStringValue == SILENCE_IS_GOLDEN
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.",
-// cc = cc.callContext
-// ) {
-// bank.id.length > 3
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidJsonFormat BANK_ID can not contain space characters",
-// cc = cc.callContext
-// ) {
-// !bank.id.contains(" ")
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidJsonFormat BANK_ID can not contain `::::` characters",
-// cc = cc.callContext
-// ) {
-// !`checkIfContains::::`(bank.id)
-// }
-//
-// (success, callContext) <- NewStyle.function.createOrUpdateBank(
-// bank.id,
-// bank.full_name,
-// bank.short_name,
-// bank.logo,
-// bank.website,
-// bank.bank_routings
-// .find(_.scheme == "BIC")
-// .map(_.address)
-// .getOrElse(""),
-// "",
-// bank.bank_routings
-// .filterNot(_.scheme == "BIC")
-// .headOption
-// .map(_.scheme)
-// .getOrElse(""),
-// bank.bank_routings
-// .filterNot(_.scheme == "BIC")
-// .headOption
-// .map(_.address)
-// .getOrElse(""),
-// cc.callContext
-// )
-// entitlements <- NewStyle.function.getEntitlementsByUserId(
-// cc.userId,
-// callContext
-// )
-// entitlementsByBank = entitlements.filter(_.bankId == bank.id)
-// _ <- entitlementsByBank
-// .filter(_.roleName == CanCreateEntitlementAtOneBank.toString())
-// .size > 0 match {
-// case true =>
-// // Already has entitlement
-// Future()
-// case false =>
-// Future(
-// Entitlement.entitlement.vend.addEntitlement(
-// bank.id,
-// cc.userId,
-// CanCreateEntitlementAtOneBank.toString()
-// )
-// )
-// }
-// _ <- entitlementsByBank
-// .filter(
-// _.roleName == CanReadDynamicResourceDocsAtOneBank.toString()
-// )
-// .size > 0 match {
-// case true =>
-// // Already has entitlement
-// Future()
-// case false =>
-// Future(
-// Entitlement.entitlement.vend.addEntitlement(
-// bank.id,
-// cc.userId,
-// CanReadDynamicResourceDocsAtOneBank.toString()
-// )
-// )
-// }
-// } yield {
-// (
-// JSONFactory400.createBankJSON400(success),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createDirectDebit,
-// implementedInApiVersion,
-// nameOf(createDirectDebit),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/direct-debit",
-// "Create Direct Debit",
-// s"""Create direct debit for an account.
-// |
-// |""",
-// postDirectDebitJsonV400,
-// directDebitJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// NoViewPermission,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// CustomerNotFoundByCustomerId,
-// UserNotFoundByUserId,
-// CounterpartyNotFoundByCounterpartyId,
-// UnknownError
-// ),
-// List(apiTagDirectDebit, apiTagAccount)
-// )
-//
-// lazy val createDirectDebit: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "direct-debit" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$NoViewPermission can_create_direct_debit. Current ViewId($viewId)",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_CREATE_DIRECT_DEBIT)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostDirectDebitJsonV400]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// postJson.customer_id,
-// callContext
-// )
-// _ <- Users.users.vend
-// .getUserByUserIdFuture(postJson.user_id) map { x =>
-// unboxFullOrFail(
-// x,
-// callContext,
-// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})"
-// )
-// }
-// (_, callContext) <- NewStyle.function
-// .getCounterpartyByCounterpartyId(
-// CounterpartyId(postJson.counterparty_id),
-// callContext
-// )
-// (directDebit, callContext) <- NewStyle.function.createDirectDebit(
-// bankId.value,
-// accountId.value,
-// postJson.customer_id,
-// postJson.user_id,
-// postJson.counterparty_id,
-// if (postJson.date_signed.isDefined) postJson.date_signed.get
-// else new Date(),
-// postJson.date_starts,
-// postJson.date_expires,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createDirectDebitJSON(directDebit),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createDirectDebitManagement,
-// implementedInApiVersion,
-// nameOf(createDirectDebitManagement),
-// "POST",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/direct-debit",
-// "Create Direct Debit (management)",
-// s"""Create direct debit for an account.
-// |
-// |""",
-// postDirectDebitJsonV400,
-// directDebitJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// NoViewPermission,
-// InvalidJsonFormat,
-// CustomerNotFoundByCustomerId,
-// UserNotFoundByUserId,
-// CounterpartyNotFoundByCounterpartyId,
-// UnknownError
-// ),
-// List(apiTagDirectDebit, apiTagAccount),
-// Some(List(canCreateDirectDebitAtOneBank))
-// )
-//
-// lazy val createDirectDebitManagement: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "direct-debit" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 "
-// for {
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostDirectDebitJsonV400]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// postJson.customer_id,
-// cc.callContext
-// )
-// _ <- Users.users.vend
-// .getUserByUserIdFuture(postJson.user_id) map { x =>
-// unboxFullOrFail(
-// x,
-// callContext,
-// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})"
-// )
-// }
-// (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(
-// CounterpartyId(postJson.counterparty_id),
-// callContext
-// )
-// (directDebit, callContext) <- NewStyle.function.createDirectDebit(
-// bankId.value,
-// accountId.value,
-// postJson.customer_id,
-// postJson.user_id,
-// postJson.counterparty_id,
-// if (postJson.date_signed.isDefined) postJson.date_signed.get
-// else new Date(),
-// postJson.date_starts,
-// postJson.date_expires,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createDirectDebitJSON(directDebit),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createStandingOrder,
-// implementedInApiVersion,
-// nameOf(createStandingOrder),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/standing-order",
-// "Create Standing Order",
-// s"""Create standing order for an account.
-// |
-// |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’}
-// |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}}
-// |
-// |""",
-// postStandingOrderJsonV400,
-// standingOrderJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// NoViewPermission,
-// InvalidJsonFormat,
-// InvalidNumber,
-// InvalidISOCurrencyCode,
-// CustomerNotFoundByCustomerId,
-// UserNotFoundByUserId,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagStandingOrder, apiTagAccount)
-// )
-//
-// lazy val createStandingOrder: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "standing-order" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$NoViewPermission can_create_standing_order. Current ViewId($viewId)",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_CREATE_STANDING_ORDER)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostStandingOrderJsonV400]
-// }
-// amountValue <- NewStyle.function.tryons(
-// s"$InvalidNumber Current input is ${postJson.amount.amount} ",
-// 400,
-// callContext
-// ) {
-// BigDecimal(postJson.amount.amount)
-// }
-// _ <- Helper.booleanToFuture(
-// s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'",
-// cc = callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(postJson.amount.currency)
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// postJson.customer_id,
-// callContext
-// )
-// _ <- Users.users.vend
-// .getUserByUserIdFuture(postJson.user_id) map { x =>
-// unboxFullOrFail(
-// x,
-// callContext,
-// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})"
-// )
-// }
-// (_, callContext) <- NewStyle.function
-// .getCounterpartyByCounterpartyId(
-// CounterpartyId(postJson.counterparty_id),
-// callContext
-// )
-// (directDebit, callContext) <- NewStyle.function.createStandingOrder(
-// bankId.value,
-// accountId.value,
-// postJson.customer_id,
-// postJson.user_id,
-// postJson.counterparty_id,
-// amountValue,
-// postJson.amount.currency,
-// postJson.when.frequency,
-// postJson.when.detail,
-// if (postJson.date_signed.isDefined) postJson.date_signed.get
-// else new Date(),
-// postJson.date_starts,
-// postJson.date_expires,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createStandingOrderJSON(directDebit),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createStandingOrderManagement,
-// implementedInApiVersion,
-// nameOf(createStandingOrderManagement),
-// "POST",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/standing-order",
-// "Create Standing Order (management)",
-// s"""Create standing order for an account.
-// |
-// |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’}
-// |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}}
-// |
-// |
-// |""",
-// postStandingOrderJsonV400,
-// standingOrderJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// NoViewPermission,
-// InvalidJsonFormat,
-// InvalidNumber,
-// InvalidISOCurrencyCode,
-// CustomerNotFoundByCustomerId,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagStandingOrder, apiTagAccount),
-// Some(List(canCreateStandingOrderAtOneBank))
-// )
-//
-// lazy val createStandingOrderManagement: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "standing-order" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 "
-// for {
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostStandingOrderJsonV400]
-// }
-// amountValue <- NewStyle.function.tryons(
-// s"$InvalidNumber Current input is ${postJson.amount.amount} ",
-// 400,
-// cc.callContext
-// ) {
-// BigDecimal(postJson.amount.amount)
-// }
-// _ <- Helper.booleanToFuture(
-// s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'",
-// cc = cc.callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(postJson.amount.currency)
-// }
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// postJson.customer_id,
-// cc.callContext
-// )
-// _ <- Users.users.vend
-// .getUserByUserIdFuture(postJson.user_id) map { x =>
-// unboxFullOrFail(
-// x,
-// callContext,
-// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})"
-// )
-// }
-// (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(
-// CounterpartyId(postJson.counterparty_id),
-// callContext
-// )
-// (directDebit, callContext) <- NewStyle.function.createStandingOrder(
-// bankId.value,
-// accountId.value,
-// postJson.customer_id,
-// postJson.user_id,
-// postJson.counterparty_id,
-// amountValue,
-// postJson.amount.currency,
-// postJson.when.frequency,
-// postJson.when.detail,
-// if (postJson.date_signed.isDefined) postJson.date_signed.get
-// else new Date(),
-// postJson.date_starts,
-// postJson.date_expires,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createStandingOrderJSON(directDebit),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// grantUserAccessToView,
-// implementedInApiVersion,
-// "grantUserAccessToView",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/grant",
-// "Grant User access to View",
-// s"""Grants the User identified by USER_ID access to the view identified by VIEW_ID.
-// |
-// |${userAuthenticationMessage(
-// true
-// )} and the user needs to be account holder.
-// |
-// |""",
-// postAccountAccessJsonV400,
-// viewJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount,
-// InvalidJsonFormat,
-// UserNotFoundById,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotGrantAccountAccess,
-// UnknownError
-// ),
-// List(
-// apiTagAccountAccess,
-// apiTagView,
-// apiTagAccount,
-// apiTagUser,
-// apiTagOwnerRequired
-// )
-// )
-//
-// lazy val grantUserAccessToView: OBPEndpoint = {
-// // add access for specific user to a specific system view
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "account-access" :: "grant" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostAccountAccessJsonV400]
-// }
-// msg =
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${postJson.view.view_id}) and current UserId(${u.userId})"
-// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) {
-// APIUtil.canGrantAccessToView(
-// bankId,
-// accountId,
-// ViewId(postJson.view.view_id),
-// u,
-// callContext
-// )
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(
-// postJson.user_id,
-// callContext
-// )
-// view <- getView(bankId, accountId, postJson.view, callContext)
-// addedView <- grantAccountAccessToUser(
-// bankId,
-// accountId,
-// user,
-// view,
-// callContext
-// )
-// } yield {
-// val viewJson = JSONFactory300.createViewJSON(addedView)
-// (viewJson, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUserWithAccountAccess,
-// implementedInApiVersion,
-// nameOf(createUserWithAccountAccess),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/user-account-access",
-// "Create (DAuth) User with Account Access",
-// s"""This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain.
-// |
-// |Put the smart contract address in username
-// |
-// |For provider use "dauth"
-// |
-// |This endpoint will create the (DAuth) User with username and provider if the User does not already exist.
-// |
-// |${userAuthenticationMessage(
-// true
-// )} and the logged in user needs to be account holder.
-// |
-// |For information about DAuth see below:
-// |
-// |${getGlossaryItem("DAuth")}
-// |
-// |""",
-// postCreateUserAccountAccessJsonV400,
-// List(viewJsonV300),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount,
-// InvalidJsonFormat,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotGrantAccountAccess,
-// UnknownError
-// ),
-// List(
-// apiTagAccountAccess,
-// apiTagView,
-// apiTagAccount,
-// apiTagUser,
-// apiTagOwnerRequired,
-// apiTagDAuth
-// )
-// )
-//
-// lazy val createUserWithAccountAccess: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "user-account-access" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostCreateUserAccountAccessJsonV400 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostCreateUserAccountAccessJsonV400]
-// }
-// // provider must start with dauth., can not create other provider users.
-// _ <- Helper.booleanToFuture(
-// s"$InvalidUserProvider The user.provider must be start with 'dauth.'",
-// cc = Some(cc)
-// ) {
-// postJson.provider.startsWith("dauth.")
-// }
-// viewIdList = postJson.views.map(view => ViewId(view.view_id))
-// msg =
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${viewIdList.mkString}) and current UserId(${u.userId})"
-// _ <- Helper.booleanToFuture(msg, 403, cc = Some(cc)) {
-// APIUtil.canGrantAccessToMultipleViews(
-// bankId,
-// accountId,
-// viewIdList,
-// u,
-// callContext
-// )
-// }
-// (targetUser, callContext) <- NewStyle.function
-// .getOrCreateResourceUser(
-// postJson.provider,
-// postJson.username,
-// cc.callContext
-// )
-// views <- getViews(bankId, accountId, postJson, callContext)
-// addedView <- grantMultpleAccountAccessToUser(
-// bankId,
-// accountId,
-// targetUser,
-// views,
-// callContext
-// )
-// } yield {
-// val viewsJson = addedView.map(JSONFactory300.createViewJSON(_))
-// (viewsJson, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// revokeUserAccessToView,
-// implementedInApiVersion,
-// "revokeUserAccessToView",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/revoke",
-// "Revoke User access to View",
-// s"""Revoke the User identified by USER_ID access to the view identified by VIEW_ID.
-// |
-// |${userAuthenticationMessage(
-// true
-// )} and the user needs to be account holder.
-// |
-// |""",
-// postAccountAccessJsonV400,
-// revokedJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserLacksPermissionCanRevokeAccessToViewForTargetAccount,
-// InvalidJsonFormat,
-// UserNotFoundById,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotRevokeAccountAccess,
-// CannotFindAccountAccess,
-// UnknownError
-// ),
-// List(
-// apiTagAccountAccess,
-// apiTagView,
-// apiTagAccount,
-// apiTagUser,
-// apiTagOwnerRequired
-// )
-// )
-//
-// lazy val revokeUserAccessToView: OBPEndpoint = {
-// // add access for specific user to a specific system view
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "account-access" :: "revoke" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostAccountAccessJsonV400]
-// }
-// viewId = ViewId(postJson.view.view_id)
-// msg =
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${viewId}) and current UserId(${u.userId})"
-// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) {
-// APIUtil.canRevokeAccessToView(
-// bankId,
-// accountId,
-// viewId,
-// u,
-// callContext
-// )
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(
-// postJson.user_id,
-// cc.callContext
-// )
-// view <- postJson.view.is_system match {
-// case true => ViewNewStyle.systemView(viewId, callContext)
-// case false =>
-// ViewNewStyle.customView(
-// viewId,
-// BankIdAccountId(bankId, accountId),
-// callContext
-// )
-// }
-// revoked <- postJson.view.is_system match {
-// case true =>
-// ViewNewStyle.revokeAccessToSystemView(
-// bankId,
-// accountId,
-// view,
-// user,
-// callContext
-// )
-// case false =>
-// ViewNewStyle.revokeAccessToCustomView(view, user, callContext)
-// }
-// } yield {
-// (RevokedJsonV400(revoked), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// revokeGrantUserAccessToViews,
-// implementedInApiVersion,
-// "revokeGrantUserAccessToViews",
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access",
-// "Revoke/Grant User access to View",
-// s"""Revoke/Grant the logged in User access to the views identified by json.
-// |
-// |${userAuthenticationMessage(
-// true
-// )} and the user needs to be an account holder or has owner view access.
-// |
-// |""",
-// postRevokeGrantAccountAccessJsonV400,
-// revokedJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount,
-// InvalidJsonFormat,
-// UserNotFoundById,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotRevokeAccountAccess,
-// CannotFindAccountAccess,
-// UnknownError
-// ),
-// List(
-// apiTagAccountAccess,
-// apiTagView,
-// apiTagAccount,
-// apiTagUser,
-// apiTagOwnerRequired
-// )
-// )
-//
-// lazy val revokeGrantUserAccessToViews: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "account-access" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostRevokeGrantAccountAccessJsonV400]
-// }
-// msg =
-// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${postJson.views.mkString}) and current UserId(${u.userId})"
-// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) {
-// APIUtil.canRevokeAccessToAllViews(bankId, accountId, u, callContext)
-// }
-// _ <- Future(
-// Views.views.vend
-// .revokeAccountAccessByUser(bankId, accountId, u, callContext)
-// ) map {
-// unboxFullOrFail(_, callContext, s"Cannot revoke")
-// }
-// grantViews = for (viewId <- postJson.views)
-// yield BankIdAccountIdViewId(bankId, accountId, ViewId(viewId))
-// _ <- Future(
-// Views.views.vend
-// .grantAccessToMultipleViews(grantViews, u, callContext)
-// ) map {
-// unboxFullOrFail(
-// _,
-// callContext,
-// s"Cannot grant the views: ${postJson.views.mkString(",")}"
-// )
-// }
-// } yield {
-// (RevokedJsonV400(true), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomerAttribute,
-// implementedInApiVersion,
-// nameOf(createCustomerAttribute),
-// "POST",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/attribute",
-// "Create Customer Attribute",
-// s""" Create Customer Attribute
-// |
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// customerAttributeJsonV400,
-// customerAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(
-// List(
-// canCreateCustomerAttributeAtOneBank,
-// canCreateCustomerAttributeAtAnyBank
-// )
-// )
-// )
-//
-// lazy val createCustomerAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "customers" :: customerId :: "attribute" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[CustomerAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// customerAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// CustomerAttributeType.withName(postedData.`type`)
-// }
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidCustomerBankId
-// .replaceAll("Bank Id.", s"Bank Id ($bankId).")
-// .replaceAll("The Customer", s"The Customer($customerId)"),
-// cc = callContext
-// ) { customer.bankId == bankId }
-// (accountAttribute, callContext) <- NewStyle.function
-// .createOrUpdateCustomerAttribute(
-// BankId(bankId),
-// CustomerId(customerId),
-// None,
-// postedData.name,
-// customerAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerAttributeJson(accountAttribute),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateCustomerAttribute,
-// implementedInApiVersion,
-// nameOf(updateCustomerAttribute),
-// "PUT",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID",
-// "Update Customer Attribute",
-// s""" Update Customer Attribute
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// customerAttributeJsonV400,
-// customerAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(
-// List(
-// canUpdateCustomerAttributeAtOneBank,
-// canUpdateCustomerAttributeAtAnyBank
-// )
-// )
-// )
-//
-// lazy val updateCustomerAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400"
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[CustomerAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// customerAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// CustomerAttributeType.withName(postedData.`type`)
-// }
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidCustomerBankId
-// .replaceAll("Bank Id.", s"Bank Id ($bankId).")
-// .replaceAll("The Customer", s"The Customer($customerId)"),
-// cc = callContext
-// ) { customer.bankId == bankId }
-// (accountAttribute, callContext) <- NewStyle.function
-// .getCustomerAttributeById(
-// customerAttributeId,
-// callContext
-// )
-// (accountAttribute, callContext) <- NewStyle.function
-// .createOrUpdateCustomerAttribute(
-// BankId(bankId),
-// CustomerId(customerId),
-// Some(customerAttributeId),
-// postedData.name,
-// customerAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerAttributeJson(accountAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAttributes,
-// implementedInApiVersion,
-// nameOf(getCustomerAttributes),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes",
-// "Get Customer Attributes",
-// s""" Get Customer Attributes
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(
-// List(
-// canGetCustomerAttributesAtOneBank,
-// canGetCustomerAttributesAtAnyBank
-// )
-// )
-// )
-//
-// lazy val getCustomerAttributes: OBPEndpoint = {
-// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidCustomerBankId
-// .replaceAll("Bank Id.", s"Bank Id ($bankId).")
-// .replaceAll("The Customer", s"The Customer($customerId)"),
-// cc = callContext
-// ) { customer.bankId == bankId }
-// (accountAttribute, callContext) <- NewStyle.function
-// .getCustomerAttributes(
-// BankId(bankId),
-// CustomerId(customerId),
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerAttributesJson(accountAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAttributeById,
-// implementedInApiVersion,
-// nameOf(getCustomerAttributeById),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/ATTRIBUTE_ID",
-// "Get Customer Attribute By Id",
-// s""" Get Customer Attribute By Id
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(
-// List(canGetCustomerAttributeAtOneBank, canGetCustomerAttributeAtAnyBank)
-// )
-// )
-//
-// lazy val getCustomerAttributeById: OBPEndpoint = {
-// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidCustomerBankId
-// .replaceAll("Bank Id.", s"Bank Id ($bankId).")
-// .replaceAll("The Customer", s"The Customer($customerId)"),
-// cc = callContext
-// ) { customer.bankId == bankId }
-// (accountAttribute, callContext) <- NewStyle.function
-// .getCustomerAttributeById(
-// customerAttributeId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerAttributeJson(accountAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersByAttributes,
-// implementedInApiVersion,
-// nameOf(getCustomersByAttributes),
-// "GET",
-// "/banks/BANK_ID/customers",
-// "Get Customers by ATTRIBUTES",
-// s"""Gets the Customers specified by attributes
-// |
-// |URL params example: /banks/some-bank-id/customers?name=John&age=8
-// |URL params example: /banks/some-bank-id/customers?&limit=50&offset=1
-// |
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "customers",
-// List(customerWithAttributesJsonV310)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersByAttributes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customerIds, callContext) <- NewStyle.function
-// .getCustomerIdsByAttributeNameValues(bankId, req.params, Some(cc))
-// list: List[CustomerWithAttributesJsonV310] <- {
-// val listCustomerFuture
-// : List[Future[CustomerWithAttributesJsonV310]] =
-// customerIds.map { customerId =>
-// val customerFuture = NewStyle.function
-// .getCustomerByCustomerId(customerId.value, callContext)
-// customerFuture.flatMap { customerAndCc =>
-// val (customer, cc) = customerAndCc
-// NewStyle.function
-// .getCustomerAttributes(bankId, customerId, cc)
-// .map { attributesAndCc =>
-// val (attributes, _) = attributesAndCc
-// JSONFactory310.createCustomerWithAttributesJson(
-// customer,
-// attributes
-// )
-// }
-// }
-// }
-// Future.sequence(listCustomerFuture)
-// }
-// } yield {
-// (ListResult("customers", list), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionAttribute,
-// implementedInApiVersion,
-// nameOf(createTransactionAttribute),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attribute",
-// "Create Transaction Attribute",
-// s""" Create Transaction Attribute
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionAttributeJsonV400,
-// transactionAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canCreateTransactionAttributeAtOneBank))
-// )
-//
-// lazy val createTransactionAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transactions" :: TransactionId(
-// transactionId
-// ) :: "attribute" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400 "
-// for {
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[TransactionAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// transactionAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// TransactionAttributeType.withName(postedData.`type`)
-// }
-// (accountAttribute, callContext) <- NewStyle.function
-// .createOrUpdateTransactionAttribute(
-// bankId,
-// transactionId,
-// None,
-// postedData.name,
-// transactionAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionAttributeJson(accountAttribute),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateTransactionAttribute,
-// implementedInApiVersion,
-// nameOf(updateTransactionAttribute),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ACCOUNT_ATTRIBUTE_ID",
-// "Update Transaction Attribute",
-// s""" Update Transaction Attribute
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionAttributeJsonV400,
-// transactionAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canUpdateTransactionAttributeAtOneBank))
-// )
-//
-// lazy val updateTransactionAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transactions" :: TransactionId(
-// transactionId
-// ) :: "attributes" :: transactionAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400"
-// for {
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[TransactionAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// transactionAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// TransactionAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getTransactionAttributeById(
-// transactionAttributeId,
-// callContext
-// )
-// (transactionAttribute, callContext) <- NewStyle.function
-// .createOrUpdateTransactionAttribute(
-// bankId,
-// transactionId,
-// Some(transactionAttributeId),
-// postedData.name,
-// transactionAttributeType,
-// postedData.value,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionAttributeJson(
-// transactionAttribute
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionAttributes,
-// implementedInApiVersion,
-// nameOf(getTransactionAttributes),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes",
-// "Get Transaction Attributes",
-// s""" Get Transaction Attributes
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canGetTransactionAttributesAtOneBank))
-// )
-//
-// lazy val getTransactionAttributes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transactions" :: TransactionId(
-// transactionId
-// ) :: "attributes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// (accountAttribute, callContext) <- NewStyle.function
-// .getTransactionAttributes(
-// bankId,
-// transactionId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionAttributesJson(accountAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionAttributeById,
-// implementedInApiVersion,
-// nameOf(getTransactionAttributeById),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ATTRIBUTE_ID",
-// "Get Transaction Attribute By Id",
-// s""" Get Transaction Attribute By Id
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canGetTransactionAttributeAtOneBank))
-// )
-//
-// lazy val getTransactionAttributeById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: "transactions" :: TransactionId(
-// transactionId
-// ) :: "attributes" :: transactionAttributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// (accountAttribute, callContext) <- NewStyle.function
-// .getTransactionAttributeById(
-// transactionAttributeId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createTransactionAttributeJson(accountAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createHistoricalTransactionAtBank,
-// implementedInApiVersion,
-// nameOf(createHistoricalTransactionAtBank),
-// "POST",
-// "/banks/BANK_ID/management/historical/transactions",
-// "Create Historical Transactions ",
-// s"""
-// |Create historical transactions at one Bank
-// |
-// |Use this endpoint to create transactions between any two accounts at the same bank.
-// |From account and to account must be at the same bank.
-// |Example:
-// |{
-// | "from_account_id": "1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// | "to_account_id": "2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// | "value": {
-// | "currency": "GBP",
-// | "amount": "10"
-// | },
-// | "description": "this is for work",
-// | "posted": "2017-09-19T02:31:05Z",
-// | "completed": "2017-09-19T02:31:05Z",
-// | "type": "SANDBOX_TAN",
-// | "charge_policy": "SHARED"
-// |}
-// |
-// |This call is experimental.
-// """.stripMargin,
-// postHistoricalTransactionAtBankJson,
-// postHistoricalTransactionResponseJson,
-// List(
-// InvalidJsonFormat,
-// BankNotFound,
-// AccountNotFound,
-// CounterpartyNotFoundByCounterpartyId,
-// InvalidNumber,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest),
-// Some(List(canCreateHistoricalTransactionAtBank))
-// )
-//
-// lazy val createHistoricalTransactionAtBank: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "management" :: "historical" :: "transactions" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId.value,
-// u.userId,
-// ApiRole.canCreateHistoricalTransactionAtBank,
-// callContext
-// )
-//
-// // Check the input JSON format, here is just check the common parts of all four types
-// transDetailsJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostHistoricalTransactionJson ",
-// 400,
-// callContext
-// ) {
-// json.extract[PostHistoricalTransactionAtBankJson]
-// }
-// (fromAccount, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// bankId,
-// AccountId(transDetailsJson.from_account_id),
-// callContext
-// )
-// (toAccount, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// bankId,
-// AccountId(transDetailsJson.to_account_id),
-// callContext
-// )
-// amountNumber <- NewStyle.function.tryons(
-// s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ",
-// 400,
-// callContext
-// ) {
-// BigDecimal(transDetailsJson.value.amount)
-// }
-// _ <- Helper.booleanToFuture(
-// s"${NotPositiveAmount} Current input is: '${amountNumber}'",
-// cc = callContext
-// ) {
-// amountNumber > BigDecimal("0")
-// }
-// posted <- NewStyle.function.tryons(
-// s"$InvalidDateFormat Current `posted` field is ${transDetailsJson.posted}. Please use this format ${DateWithSecondsFormat.toPattern}! ",
-// 400,
-// callContext
-// ) {
-// new SimpleDateFormat(DateWithSeconds).parse(
-// transDetailsJson.posted
-// )
-// }
-// completed <- NewStyle.function.tryons(
-// s"$InvalidDateFormat Current `completed` field is ${transDetailsJson.completed}. Please use this format ${DateWithSecondsFormat.toPattern}! ",
-// 400,
-// callContext
-// ) {
-// new SimpleDateFormat(DateWithSeconds).parse(
-// transDetailsJson.completed
-// )
-// }
-// // Prevent default value for transaction request type (at least).
-// _ <- Helper.booleanToFuture(
-// s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'",
-// cc = callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(transDetailsJson.value.currency)
-// }
-// amountOfMoneyJson = AmountOfMoneyJsonV121(
-// transDetailsJson.value.currency,
-// transDetailsJson.value.amount
-// )
-// chargePolicy = transDetailsJson.charge_policy
-// // There is no constraint for the type at the moment
-// transactionType = transDetailsJson.`type`
-// (transactionId, callContext) <- NewStyle.function
-// .makeHistoricalPayment(
-// fromAccount,
-// toAccount,
-// posted,
-// completed,
-// amountNumber,
-// transDetailsJson.value.currency,
-// transDetailsJson.description,
-// transactionType,
-// chargePolicy,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createPostHistoricalTransactionResponseJson(
-// bankId,
-// transactionId,
-// fromAccount.accountId,
-// toAccount.accountId,
-// value = amountOfMoneyJson,
-// description = transDetailsJson.description,
-// posted,
-// completed,
-// transactionRequestType = transactionType,
-// chargePolicy = transDetailsJson.charge_policy
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionRequest,
-// implementedInApiVersion,
-// nameOf(getTransactionRequest),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests/TRANSACTION_REQUEST_ID",
-// "Get Transaction Request.",
-// """Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID and for account specified by ACCOUNT_ID at bank specified by BANK_ID.
-// |
-// |The VIEW_ID specified must be 'owner' and the user must have access to this view.
-// |
-// |Version 2.0.0 now returns charge information.
-// |
-// |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:
-// |
-// |* Transaction Request Id
-// |* Type
-// |* Status (INITIATED, COMPLETED)
-// |* Challenge (in order to confirm the request)
-// |* From Bank / Account
-// |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)
-// |* Related Transactions
-// |
-// |PSD2 Context: PSD2 requires transparency of charges to the customer.
-// |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.
-// |The customer can proceed with the Transaction by answering the security challenge.
-// |
-// """.stripMargin,
-// EmptyBody,
-// transactionRequestWithChargeJSON210,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// GetTransactionRequestsException,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val getTransactionRequest: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "transaction-requests" :: TransactionRequestId(
-// requestId
-// ) :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- NewStyle.function.isEnabledTransactionRequests(callContext)
-// view <- ViewNewStyle.checkAccountAccessAndGetView(
-// viewId,
-// BankIdAccountId(bankId, accountId),
-// Full(u),
-// callContext
-// )
-// _ <- Helper.booleanToFuture(
-// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})",
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_SEE_TRANSACTION_REQUESTS)
-// }
-// (transactionRequest, callContext) <- NewStyle.function
-// .getTransactionRequestImpl(requestId, callContext)
-// } yield {
-// val json = JSONFactory210.createTransactionRequestWithChargeJSON(
-// transactionRequest
-// )
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPrivateAccountsAtOneBank,
-// implementedInApiVersion,
-// "getPrivateAccountsAtOneBank",
-// "GET",
-// "/banks/BANK_ID/accounts",
-// "Get Accounts at Bank",
-// s"""
-// |Returns the list of accounts at BANK_ID that the user has access to.
-// |For each account the API returns the account ID and the views available to the user..
-// |Each account must have at least one private View.
-// |
-// |optional request parameters for filter with attributes
-// |URL params example: /banks/some-bank-id/accounts?&limit=50&offset=1
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// basicAccountsJSON,
-// List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError),
-// List(apiTagAccount, apiTagPrivateData, apiTagPublicData)
-// )
-//
-// lazy val getPrivateAccountsAtOneBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), bank, callContext) <- SS.userBank
-// (privateViewsUserCanAccessAtOneBank, privateAccountAccess) =
-// Views.views.vend.privateViewsUserCanAccessAtBank(u, bankId)
-// params = req.params
-// .filterNot(
-// _._1 == PARAM_TIMESTAMP
-// ) // ignore `_timestamp_` parameter, it is for invalid Browser caching
-// .filterNot(_._1 == PARAM_LOCALE)
-// privateAccountAccess2 <-
-// if (params.isEmpty || privateAccountAccess.isEmpty) {
-// Future.successful(privateAccountAccess)
-// } else {
-// AccountAttributeX.accountAttributeProvider.vend
-// .getAccountIdsByParams(bankId, params)
-// .map { boxedAccountIds =>
-// val accountIds = boxedAccountIds.getOrElse(Nil)
-// privateAccountAccess.filter(aa =>
-// accountIds.contains(aa.account_id.get)
-// )
-// }
-// }
-// (availablePrivateAccounts, callContext) <- bank.privateAccountsFuture(
-// privateAccountAccess2,
-// callContext
-// )
-// } yield {
-// val bankAccounts = Implementations2_0_0.processAccounts(
-// privateViewsUserCanAccessAtOneBank,
-// availablePrivateAccounts
-// )
-// (bankAccounts, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createConsumer,
-// implementedInApiVersion,
-// "createConsumer",
-// "POST",
-// "/management/consumers",
-// "Post a Consumer",
-// s"""Create a Consumer (Authenticated access).
-// |
-// |""",
-// ConsumerPostJSON(
-// "Test",
-// "Web",
-// "Description",
-// "some@email.com",
-// "redirecturl",
-// "createdby",
-// true,
-// new Date(),
-// """-----BEGIN CERTIFICATE-----
-// |client_certificate_content
-// |-----END CERTIFICATE-----""".stripMargin
-// ),
-// consumerJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canCreateConsumer))
-// )
-//
-// lazy val createConsumer: OBPEndpoint = {
-// case "management" :: "consumers" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (postedJson, appType) <- NewStyle.function.tryons(
-// InvalidJsonFormat,
-// 400,
-// callContext
-// ) {
-// val consumerPostJSON = json.extract[ConsumerPostJSON]
-// val appType =
-// if (consumerPostJSON.app_type.equals("Confidential"))
-// AppType.valueOf("Confidential")
-// else AppType.valueOf("Public")
-// (consumerPostJSON, appType)
-// }
-// _ <- NewStyle.function.hasEntitlement(
-// "",
-// u.userId,
-// ApiRole.canCreateConsumer,
-// callContext
-// )
-// (consumer, callContext) <- createConsumerNewStyle(
-// key = Some(Helpers.randomString(40).toLowerCase),
-// secret = Some(Helpers.randomString(40).toLowerCase),
-// isActive = Some(postedJson.enabled),
-// name = Some(postedJson.app_name),
-// appType = Some(appType),
-// description = Some(postedJson.description),
-// developerEmail = Some(postedJson.developer_email),
-// company = None,
-// redirectURL = Some(postedJson.redirect_url),
-// createdByUserId = Some(u.userId),
-// clientCertificate = Some(postedJson.clientCertificate),
-// logoURL = None,
-// callContext
-// )
-// user <- Users.users.vend.getUserByUserIdFuture(u.userId)
-// } yield {
-// // Format the data as json
-// val json = JSONFactory400.createConsumerJSON(consumer, user)
-// // Return
-// (json, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersAtAnyBank,
-// implementedInApiVersion,
-// nameOf(getCustomersAtAnyBank),
-// "GET",
-// "/customers",
-// "Get Customers at Any Bank",
-// s"""Get Customers at Any Bank.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customersJsonV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersAtAllBanks))
-// )
-// lazy val getCustomersAtAnyBank: OBPEndpoint = {
-// case "customers" :: Nil JsonGet _ => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(
-// cc.url,
-// List("limit", "offset", "sort_direction"),
-// cc.callContext
-// )
-// (customers, callContext) <- getCustomersAtAllBanks(
-// callContext,
-// requestParams
-// )
-// } yield {
-// (
-// JSONFactory300.createCustomersJson(customers.sortBy(_.bankId)),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersMinimalAtAnyBank,
-// implementedInApiVersion,
-// nameOf(getCustomersMinimalAtAnyBank),
-// "GET",
-// "/customers-minimal",
-// "Get Customers Minimal at Any Bank",
-// s"""Get Customers Minimal at Any Bank.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customersMinimalJsonV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersMinimalAtAllBanks))
-// )
-// lazy val getCustomersMinimalAtAnyBank: OBPEndpoint = {
-// case "customers-minimal" :: Nil JsonGet _ => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(
-// cc.url,
-// List("limit", "offset", "sort_direction"),
-// cc.callContext
-// )
-// (customers, callContext) <- getCustomersAtAllBanks(
-// callContext,
-// requestParams
-// )
-// } yield {
-// (
-// createCustomersMinimalJson(customers.sortBy(_.bankId)),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getScopes,
-// implementedInApiVersion,
-// nameOf(getScopes),
-// "GET",
-// "/consumers/CONSUMER_ID/scopes",
-// "Get Scopes for Consumer",
-// s"""Get all the scopes for an consumer specified by CONSUMER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// scopeJsons,
-// List(
-// AuthenticatedUserIsRequired,
-// EntitlementNotFound,
-// ConsumerNotFoundByConsumerId,
-// UnknownError
-// ),
-// List(apiTagScope, apiTagConsumer)
-// )
-//
-// lazy val getScopes: OBPEndpoint = {
-// case "consumers" :: uuidOfConsumer :: "scopes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// consumer <- Future { callContext.get.consumer } map { x =>
-// unboxFullOrFail(x, callContext, InvalidConsumerCredentials)
-// }
-// _ <- Future {
-// NewStyle.function.hasEntitlementAndScope(
-// "",
-// u.userId,
-// consumer.id.get.toString,
-// canGetEntitlementsForAnyUserAtAnyBank,
-// callContext
-// )
-// } flatMap { unboxFullAndWrapIntoFuture(_) }
-// consumer <- NewStyle.function.getConsumerByConsumerId(
-// uuidOfConsumer,
-// callContext
-// )
-// primaryKeyOfConsumer = consumer.id.get.toString
-// scopes <- Future {
-// Scope.scope.vend.getScopesByConsumerId(primaryKeyOfConsumer)
-// } map { unboxFull(_) }
-// } yield (
-// JSONFactory300.createScopeJSONs(scopes),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// addScope,
-// implementedInApiVersion,
-// nameOf(addScope),
-// "POST",
-// "/consumers/CONSUMER_ID/scopes",
-// "Create Scope for a Consumer",
-// """Create Scope. Grant Role to Consumer.
-// |
-// |Scopes are used to grant System or Bank level roles to the Consumer (App). (For Account level privileges, see Views)
-// |
-// |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":""
-// |
-// |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id"
-// |
-// |""",
-// SwaggerDefinitionsJSON.createScopeJson,
-// scopeJson,
-// List(
-// AuthenticatedUserIsRequired,
-// ConsumerNotFoundById,
-// InvalidJsonFormat,
-// IncorrectRoleName,
-// EntitlementIsBankRole,
-// EntitlementIsSystemRole,
-// EntitlementAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagScope, apiTagConsumer),
-// Some(List(canCreateScopeAtAnyBank, canCreateScopeAtOneBank))
-// )
-//
-// lazy val addScope: OBPEndpoint = {
-// case "consumers" :: consumerId :: "scopes" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// consumer <- NewStyle.function.getConsumerByConsumerId(
-// consumerId,
-// callContext
-// )
-// postedData <- Future {
-// tryo { json.extract[CreateScopeJson] }
-// } map {
-// val msg =
-// s"$InvalidJsonFormat The Json body should be the $CreateScopeJson "
-// x => unboxFullOrFail(x, callContext, msg)
-// }
-// role <- Future { tryo { valueOf(postedData.role_name) } } map {
-// val msg =
-// IncorrectRoleName + postedData.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted
-// .mkString(", ")
-// x => unboxFullOrFail(x, callContext, msg)
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// if (ApiRole.valueOf(postedData.role_name).requiresBankId)
-// EntitlementIsBankRole
-// else EntitlementIsSystemRole,
-// cc = callContext
-// ) {
-// ApiRole
-// .valueOf(postedData.role_name)
-// .requiresBankId == postedData.bank_id.nonEmpty
-// }
-// allowedEntitlements =
-// canCreateScopeAtOneBank :: canCreateScopeAtAnyBank :: Nil
-// allowedEntitlementsTxt =
-// s"$UserHasMissingRoles ${allowedEntitlements.mkString(", ")}!"
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg =
-// allowedEntitlementsTxt
-// )(postedData.bank_id, u.userId, allowedEntitlements, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = BankNotFound,
-// cc = callContext
-// ) {
-// postedData.bank_id.nonEmpty == false || BankX(
-// BankId(postedData.bank_id),
-// callContext
-// ).map(_._1).isEmpty == false
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = EntitlementAlreadyExists,
-// cc = callContext
-// ) {
-// hasScope(postedData.bank_id, consumerId, role) == false
-// }
-// addedEntitlement <- Future {
-// Scope.scope.vend.addScope(
-// postedData.bank_id,
-// consumer.id.get.toString,
-// postedData.role_name
-// )
-// } map { unboxFull(_) }
-// } yield {
-// (
-// JSONFactory300.createScopeJson(addedEntitlement),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// val customerAttributeGeneralInfo =
-// s"""
-// |CustomerAttributes are used to enhance the OBP Customer object with Bank specific entities.
-// |
-// """.stripMargin
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomerAttribute,
-// implementedInApiVersion,
-// nameOf(deleteCustomerAttribute),
-// "DELETE",
-// "/banks/BANK_ID/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID",
-// "Delete Customer Attribute",
-// s""" Delete Customer Attribute
-// |
-// |$customerAttributeGeneralInfo
-// |
-// |Delete a Customer Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(
-// List(
-// canDeleteCustomerAttributeAtOneBank,
-// canDeleteCustomerAttributeAtAnyBank
-// )
-// )
-// )
-//
-// lazy val deleteCustomerAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "customers" :: "attributes" :: customerAttributeId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customerAttribute, callContext) <- NewStyle.function
-// .deleteCustomerAttribute(customerAttributeId, cc.callContext)
-// } yield {
-// (Full(customerAttribute), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(createDynamicEndpoint),
-// "POST",
-// "/management/dynamic-endpoints",
-// "Create Dynamic Endpoint",
-// s"""Create dynamic endpoints.
-// |
-// |Create dynamic endpoints with one json format swagger content.
-// |
-// |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields,
-// |please check `Endpoint Mapping` endpoints.
-// |
-// |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n
-// |when create MethodRouting for given dynamic endpoint, it will be routed to given url.
-// |
-// |""",
-// dynamicEndpointRequestBodyExample,
-// dynamicEndpointResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEndpointExists,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canCreateDynamicEndpoint))
-// )
-//
-// lazy val createDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "dynamic-endpoints" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// createDynamicEndpointMethod(None, json, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(createBankLevelDynamicEndpoint),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-endpoints",
-// "Create Bank Level Dynamic Endpoint",
-// s"""Create dynamic endpoints.
-// |
-// |Create dynamic endpoints with one json format swagger content.
-// |
-// |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields,
-// |please check `Endpoint Mapping` endpoints.
-// |
-// |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n
-// |when create MethodRouting for given dynamic endpoint, it will be routed to given url.
-// |
-// |""",
-// dynamicEndpointRequestBodyExample,
-// dynamicEndpointResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEndpointExists,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canCreateBankLevelDynamicEndpoint, canCreateDynamicEndpoint))
-// )
-//
-// lazy val createBankLevelDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(
-// bankId
-// ) :: "dynamic-endpoints" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// createDynamicEndpointMethod(Some(bankId.value), json, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateDynamicEndpointHost,
-// implementedInApiVersion,
-// nameOf(updateDynamicEndpointHost),
-// "PUT",
-// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host",
-// " Update Dynamic Endpoint Host",
-// s"""Update dynamic endpoint Host.
-// |The value can be obp_mock, dynamic_entity, or some service url.
-// |""",
-// dynamicEndpointHostJson400,
-// dynamicEndpointHostJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEntityNotFoundByDynamicEntityId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canUpdateDynamicEndpoint))
-// )
-//
-// lazy val updateDynamicEndpointHost: OBPEndpoint = {
-// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateDynamicEndpointHostMethod(None, dynamicEndpointId, json, cc)
-// }
-// }
-//
-// private def updateDynamicEndpointHostMethod(
-// bankId: Option[String],
-// dynamicEndpointId: String,
-// json: JValue,
-// cc: CallContext
-// ) = {
-// for {
-// (_, callContext) <- NewStyle.function.getDynamicEndpoint(
-// bankId,
-// dynamicEndpointId,
-// cc.callContext
-// )
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $DynamicEndpointHostJson400"
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[DynamicEndpointHostJson400]
-// }
-// (dynamicEndpoint, callContext) <- NewStyle.function
-// .updateDynamicEndpointHost(
-// bankId,
-// dynamicEndpointId,
-// postedData.host,
-// cc.callContext
-// )
-// } yield {
-// (postedData, HttpCode.`201`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelDynamicEndpointHost,
-// implementedInApiVersion,
-// nameOf(updateBankLevelDynamicEndpointHost),
-// "PUT",
-// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host",
-// " Update Bank Level Dynamic Endpoint Host",
-// s"""Update Bank Level dynamic endpoint Host.
-// |The value can be obp_mock, dynamic_entity, or some service url.
-// |""",
-// dynamicEndpointHostJson400,
-// dynamicEndpointHostJson400,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEntityNotFoundByDynamicEntityId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canUpdateBankLevelDynamicEndpoint, canUpdateDynamicEndpoint))
-// )
-//
-// lazy val updateBankLevelDynamicEndpointHost: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateDynamicEndpointHostMethod(
-// Some(bankId),
-// dynamicEndpointId,
-// json,
-// cc
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(getDynamicEndpoint),
-// "GET",
-// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID",
-// "Get Dynamic Endpoint",
-// s"""Get a Dynamic Endpoint.
-// |
-// |
-// |Get one DynamicEndpoint,
-// |
-// |""",
-// EmptyBody,
-// dynamicEndpointResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEndpointNotFoundByDynamicEndpointId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canGetDynamicEndpoint))
-// )
-//
-// lazy val getDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getDynamicEndpointMethod(None, dynamicEndpointId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDynamicEndpoints,
-// implementedInApiVersion,
-// nameOf(getDynamicEndpoints),
-// "GET",
-// "/management/dynamic-endpoints",
-// " Get Dynamic Endpoints",
-// s"""
-// |
-// |Get Dynamic Endpoints.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "dynamic_endpoints",
-// List(dynamicEndpointResponseBodyExample)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canGetDynamicEndpoints))
-// )
-//
-// lazy val getDynamicEndpoints: OBPEndpoint = {
-// case "management" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getDynamicEndpointsMethod(None, cc)
-// }
-// }
-//
-// private def getDynamicEndpointsMethod(
-// bankId: Option[String],
-// cc: CallContext
-// ) = {
-// for {
-// (dynamicEndpoints, _) <- NewStyle.function.getDynamicEndpoints(
-// bankId,
-// cc.callContext
-// )
-// } yield {
-// val resultList = dynamicEndpoints.map[JObject, List[JObject]] {
-// dynamicEndpoint =>
-// val swaggerJson = parse(dynamicEndpoint.swaggerString)
-// (
-// "user_id",
-// cc.userId
-// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson)
-// }
-// (
-// ListResult("dynamic_endpoints", resultList),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicEndpoint),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID",
-// " Get Bank Level Dynamic Endpoint",
-// s"""Get a Bank Level Dynamic Endpoint.
-// |""",
-// EmptyBody,
-// dynamicEndpointResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// DynamicEndpointNotFoundByDynamicEndpointId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canGetBankLevelDynamicEndpoint, canGetDynamicEndpoint))
-// )
-//
-// lazy val getBankLevelDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc)
-// }
-// }
-//
-// private def getDynamicEndpointMethod(
-// bankId: Option[String],
-// dynamicEndpointId: String,
-// cc: CallContext
-// ) = {
-// for {
-// (dynamicEndpoint, callContext) <- NewStyle.function.getDynamicEndpoint(
-// bankId,
-// dynamicEndpointId,
-// cc.callContext
-// )
-// } yield {
-// val swaggerJson = parse(dynamicEndpoint.swaggerString)
-// val responseJson: JObject = (
-// "user_id",
-// cc.userId
-// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson)
-// (responseJson, HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicEndpoints,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicEndpoints),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-endpoints",
-// "Get Bank Level Dynamic Endpoints",
-// s"""
-// |
-// |Get Bank Level Dynamic Endpoints.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "dynamic_endpoints",
-// List(dynamicEndpointResponseBodyExample)
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canGetBankLevelDynamicEndpoints, canGetDynamicEndpoints))
-// )
-//
-// lazy val getBankLevelDynamicEndpoints: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getDynamicEndpointsMethod(Some(bankId), cc)
-// }
-// }
-//
-// private def deleteDynamicEndpointMethod(
-// bankId: Option[String],
-// dynamicEndpointId: String,
-// cc: CallContext
-// ) = {
-// for {
-// deleted <- NewStyle.function.deleteDynamicEndpoint(
-// bankId,
-// dynamicEndpointId,
-// cc.callContext
-// )
-// } yield {
-// (deleted, HttpCode.`204`(cc.callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(deleteDynamicEndpoint),
-// "DELETE",
-// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID",
-// " Delete Dynamic Endpoint",
-// s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// DynamicEndpointNotFoundByDynamicEndpointId,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canDeleteDynamicEndpoint))
-// )
-//
-// lazy val deleteDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteDynamicEndpointMethod(None, dynamicEndpointId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelDynamicEndpoint),
-// "DELETE",
-// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID",
-// " Delete Bank Level Dynamic Endpoint",
-// s"""Delete a Bank Level DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// DynamicEndpointNotFoundByDynamicEndpointId,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi),
-// Some(List(canDeleteBankLevelDynamicEndpoint, canDeleteDynamicEndpoint))
-// )
-//
-// lazy val deleteBankLevelDynamicEndpoint: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyDynamicEndpoints,
-// implementedInApiVersion,
-// nameOf(getMyDynamicEndpoints),
-// "GET",
-// "/my/dynamic-endpoints",
-// "Get My Dynamic Endpoints",
-// s"""Get My Dynamic Endpoints.""".stripMargin,
-// EmptyBody,
-// ListResult(
-// "dynamic_endpoints",
-// List(dynamicEndpointResponseBodyExample)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi)
-// )
-//
-// lazy val getMyDynamicEndpoints: OBPEndpoint = {
-// case "my" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicEndpoints, _) <- NewStyle.function
-// .getDynamicEndpointsByUserId(cc.userId, cc.callContext)
-// } yield {
-// val resultList = dynamicEndpoints.map[JObject, List[JObject]] {
-// dynamicEndpoint =>
-// val swaggerJson = parse(dynamicEndpoint.swaggerString)
-// (
-// "user_id",
-// cc.userId
-// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson)
-// }
-// (
-// ListResult("dynamic_endpoints", resultList),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyDynamicEndpoint,
-// implementedInApiVersion,
-// nameOf(deleteMyDynamicEndpoint),
-// "DELETE",
-// "/my/dynamic-endpoints/DYNAMIC_ENDPOINT_ID",
-// "Delete My Dynamic Endpoint",
-// s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// DynamicEndpointNotFoundByDynamicEndpointId,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEndpoint, apiTagApi)
-// )
-//
-// lazy val deleteMyDynamicEndpoint: OBPEndpoint = {
-// case "my" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicEndpoint, callContext) <- NewStyle.function
-// .getDynamicEndpoint(None, dynamicEndpointId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// InvalidMyDynamicEndpointUser,
-// cc = callContext
-// ) {
-// dynamicEndpoint.userId.equals(cc.userId)
-// }
-// deleted <- NewStyle.function.deleteDynamicEndpoint(
-// None,
-// dynamicEndpointId,
-// callContext
-// )
-//
-// } yield {
-// (deleted, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateCustomerAttributeAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateCustomerAttributeAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/customer",
-// "Create or Update Customer Attribute Definition",
-// s""" Create or Update Customer Attribute Definition
-// |
-// |The category field must be one of: ${AttributeCategory.Customer}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// templateAttributeDefinitionJsonV400,
-// templateAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(List(canCreateCustomerAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateCustomerAttributeAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "customer" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Customer}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateAccountAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateAccountAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/account",
-// "Create or Update Account Attribute Definition",
-// s""" Create or Update Account Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.Account}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// accountAttributeDefinitionJsonV400,
-// accountAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute),
-// Some(List(canCreateAccountAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateAccountAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "account" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Account}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateProductAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateProductAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/product",
-// "Create or Update Product Attribute Definition",
-// s""" Create or Update Product Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.Product}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productAttributeDefinitionJsonV400,
-// productAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canCreateProductAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateProductAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "product" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Product}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// val productAttributeGeneralInfo =
-// s"""
-// |Product Attributes are used to describe a financial Product with a list of typed key value pairs.
-// |
-// |Each Product Attribute is linked to its Product by PRODUCT_CODE
-// |
-// |
-// """.stripMargin
-//
-// staticResourceDocs += ResourceDoc(
-// createProductAttribute,
-// implementedInApiVersion,
-// nameOf(createProductAttribute),
-// "POST",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attribute",
-// "Create Product Attribute",
-// s""" Create Product Attribute
-// |
-// |$productAttributeGeneralInfo
-// |
-// |Typical product attributes might be:
-// |
-// |ISIN (for International bonds)
-// |VKN (for German bonds)
-// |REDCODE (markit short code for credit derivative)
-// |LOAN_ID (e.g. used for Anacredit reporting)
-// |
-// |ISSUE_DATE (When the bond was issued in the market)
-// |MATURITY_DATE (End of life time of a product)
-// |TRADABLE
-// |
-// |See [FPML](http://www.fpml.org/) for more examples.
-// |
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productAttributeJsonV400,
-// productAttributeResponseJsonV400,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canCreateProductAttribute))
-// )
-//
-// lazy val createProductAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "attribute" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId,
-// u.userId,
-// canCreateProductAttribute,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[ProductAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// productAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// ProductAttributeType.withName(postedData.`type`)
-// }
-// (products, callContext) <- NewStyle.function.getProduct(
-// BankId(bankId),
-// ProductCode(productCode),
-// callContext
-// )
-// (productAttribute, callContext) <- NewStyle.function
-// .createOrUpdateProductAttribute(
-// BankId(bankId),
-// ProductCode(productCode),
-// None,
-// postedData.name,
-// productAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (
-// createProductAttributeJson(productAttribute),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateProductAttribute,
-// implementedInApiVersion,
-// nameOf(updateProductAttribute),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID",
-// "Update Product Attribute",
-// s""" Update Product Attribute.
-// |
-//
-// |$productAttributeGeneralInfo
-// |
-// |Update one Product Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productAttributeJsonV400,
-// productAttributeResponseJsonV400,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canUpdateProductAttribute))
-// )
-//
-// lazy val updateProductAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId,
-// u.userId,
-// canUpdateProductAttribute,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[ProductAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// productAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// ProductAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getProductAttributeById(
-// productAttributeId,
-// callContext
-// )
-// (productAttribute, callContext) <- NewStyle.function
-// .createOrUpdateProductAttribute(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(productAttributeId),
-// postedData.name,
-// productAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (
-// createProductAttributeJson(productAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProductAttribute,
-// implementedInApiVersion,
-// nameOf(getProductAttribute),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID",
-// "Get Product Attribute",
-// s""" Get Product Attribute
-// |
-// |$productAttributeGeneralInfo
-// |
-// |Get one product attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// productAttributeResponseJsonV400,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canUpdateProductAttribute))
-// )
-//
-// lazy val getProductAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId,
-// u.userId,
-// canGetProductAttribute,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// (productAttribute, callContext) <- NewStyle.function
-// .getProductAttributeById(productAttributeId, callContext)
-//
-// } yield {
-// (
-// createProductAttributeJson(productAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createProductFee,
-// implementedInApiVersion,
-// nameOf(createProductFee),
-// "POST",
-// "/banks/BANK_ID/products/PRODUCT_CODE/fee",
-// "Create Product Fee",
-// s"""Create Product Fee
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productFeeJsonV400.copy(product_fee_id = None),
-// productFeeResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canCreateProductFee))
-// )
-//
-// lazy val createProductFee: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "fee" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ",
-// 400,
-// Some(cc)
-// ) {
-// json.extract[ProductFeeJsonV400]
-// }
-// (_, callContext) <- NewStyle.function.getProduct(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(cc)
-// )
-// (productFee, callContext) <- NewStyle.function
-// .createOrUpdateProductFee(
-// BankId(bankId),
-// ProductCode(productCode),
-// None,
-// postedData.name,
-// postedData.is_active,
-// postedData.more_info,
-// postedData.value.currency,
-// postedData.value.amount,
-// postedData.value.frequency,
-// postedData.value.`type`,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createProductFeeJson(productFee), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateProductFee,
-// implementedInApiVersion,
-// nameOf(updateProductFee),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID",
-// "Update Product Fee",
-// s""" Update Product Fee.
-// |
-// |Update one Product Fee by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// productFeeJsonV400.copy(product_fee_id = None),
-// productFeeResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canUpdateProductFee))
-// )
-//
-// lazy val updateProductFee: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ",
-// 400,
-// Some(cc)
-// ) {
-// json.extract[ProductFeeJsonV400]
-// }
-// (_, callContext) <- NewStyle.function.getProduct(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(cc)
-// )
-// (_, callContext) <- NewStyle.function.getProductFeeById(
-// productFeeId,
-// callContext
-// )
-// (productFee, callContext) <- NewStyle.function
-// .createOrUpdateProductFee(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(productFeeId),
-// postedData.name,
-// postedData.is_active,
-// postedData.more_info,
-// postedData.value.currency,
-// postedData.value.amount,
-// postedData.value.frequency,
-// postedData.value.`type`,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createProductFeeJson(productFee), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProductFee,
-// implementedInApiVersion,
-// nameOf(getProductFee),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID",
-// "Get Product Fee",
-// s""" Get Product Fee
-// |
-// |Get one product fee by its id.
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |""",
-// EmptyBody,
-// productFeeResponseJsonV400,
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProductFee: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (productFee, callContext) <- NewStyle.function.getProductFeeById(
-// productFeeId,
-// Some(cc)
-// )
-// } yield {
-// (createProductFeeJson(productFee), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProductFees,
-// implementedInApiVersion,
-// nameOf(getProductFees),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE/fees",
-// "Get Product Fees",
-// s"""Get Product Fees
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |""",
-// EmptyBody,
-// productFeesResponseJsonV400,
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProductFees: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "fees" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (productFees, callContext) <- NewStyle.function
-// .getProductFeesFromProvider(
-// BankId(bankId),
-// ProductCode(productCode),
-// Some(cc)
-// )
-// } yield {
-// (createProductFeesJson(productFees), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// deleteProductFee,
-// implementedInApiVersion,
-// nameOf(deleteProductFee),
-// "DELETE",
-// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID",
-// "Delete Product Fee",
-// s"""Delete Product Fee
-// |
-// |Delete one product fee by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canDeleteProductFee))
-// )
-//
-// lazy val deleteProductFee: OBPEndpoint = {
-// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getProductFeeById(
-// productFeeId,
-// Some(cc)
-// )
-// (productFee, callContext) <- NewStyle.function.deleteProductFee(
-// productFeeId,
-// Some(cc)
-// )
-// } yield {
-// (productFee, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateBankAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateBankAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/bank",
-// "Create or Update Bank Attribute Definition",
-// s""" Create or Update Bank Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.Bank}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// bankAttributeDefinitionJsonV400,
-// bankAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute),
-// Some(List(canCreateBankAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateBankAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "bank" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Bank}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankAttribute,
-// implementedInApiVersion,
-// nameOf(createBankAttribute),
-// "POST",
-// "/banks/BANK_ID/attribute",
-// "Create Bank Attribute",
-// s""" Create Bank Attribute
-// |
-// |Typical product attributes might be:
-// |
-// |ISIN (for International bonds)
-// |VKN (for German bonds)
-// |REDCODE (markit short code for credit derivative)
-// |LOAN_ID (e.g. used for Anacredit reporting)
-// |
-// |ISSUE_DATE (When the bond was issued in the market)
-// |MATURITY_DATE (End of life time of a product)
-// |TRADABLE
-// |
-// |See [FPML](http://www.fpml.org/) for more examples.
-// |
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// bankAttributeJsonV400,
-// bankAttributeResponseJsonV400,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute),
-// Some(List(canCreateBankAttribute))
-// )
-//
-// lazy val createBankAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "attribute" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[BankAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// bankAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// BankAttributeType.withName(postedData.`type`)
-// }
-// (bankAttribute, callContext) <- NewStyle.function
-// .createOrUpdateBankAttribute(
-// BankId(bankId),
-// None,
-// postedData.name,
-// bankAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (createBankAttributeJson(bankAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAttributes,
-// implementedInApiVersion,
-// nameOf(getBankAttributes),
-// "GET",
-// "/banks/BANK_ID/attributes",
-// "Get Bank Attributes",
-// s""" Get Bank Attributes
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// bankAttributesResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute),
-// Some(List(canGetBankAttribute))
-// )
-//
-// lazy val getBankAttributes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "attributes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributes, callContext) <- NewStyle.function
-// .getBankAttributesByBank(bankId, cc.callContext)
-// } yield {
-// (createBankAttributesJson(attributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAttribute,
-// implementedInApiVersion,
-// nameOf(getBankAttribute),
-// "GET",
-// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID",
-// "Get Bank Attribute By BANK_ATTRIBUTE_ID",
-// s""" Get Bank Attribute By BANK_ATTRIBUTE_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// bankAttributeResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute),
-// Some(List(canGetBankAttribute))
-// )
-//
-// lazy val getBankAttribute: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attributes" :: bankAttributeId :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attribute, callContext) <- NewStyle.function.getBankAttributeById(
-// bankAttributeId,
-// cc.callContext
-// )
-// } yield {
-// (createBankAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankAttribute,
-// implementedInApiVersion,
-// nameOf(updateBankAttribute),
-// "PUT",
-// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID",
-// "Update Bank Attribute",
-// s""" Update Bank Attribute.
-// |
-// |Update one Bak Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// bankAttributeJsonV400,
-// bankAttributeDefinitionJsonV400,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute)
-// )
-//
-// lazy val updateBankAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId,
-// u.userId,
-// canUpdateBankAttribute,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[BankAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// productAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// BankAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getBankAttributeById(
-// bankAttributeId,
-// callContext
-// )
-// (bankAttribute, callContext) <- NewStyle.function
-// .createOrUpdateBankAttribute(
-// BankId(bankId),
-// Some(bankAttributeId),
-// postedData.name,
-// productAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (
-// createBankAttributeJson(bankAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankAttribute,
-// implementedInApiVersion,
-// nameOf(deleteBankAttribute),
-// "DELETE",
-// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID",
-// "Delete Bank Attribute",
-// s""" Delete Bank Attribute
-// |
-// |Delete a Bank Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// UserHasMissingRoles,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagBank, apiTagBankAttribute, apiTagAttribute)
-// )
-//
-// lazy val deleteBankAttribute: OBPEndpoint = {
-// case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(
-// bankId,
-// u.userId,
-// canDeleteBankAttribute,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(bankId),
-// callContext
-// )
-// (bankAttribute, callContext) <- NewStyle.function
-// .deleteBankAttribute(bankAttributeId, callContext)
-// } yield {
-// (Full(bankAttribute), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateTransactionAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateTransactionAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/transaction",
-// "Create or Update Transaction Attribute Definition",
-// s""" Create or Update Transaction Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.Transaction}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// transactionAttributeDefinitionJsonV400,
-// transactionAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canCreateTransactionAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateTransactionAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "transaction" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Transaction}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateCardAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(createOrUpdateCardAttributeDefinition),
-// "PUT",
-// "/banks/BANK_ID/attribute-definitions/card",
-// "Create or Update Card Attribute Definition",
-// s""" Create or Update Card Attribute Definition
-// |
-// |The category field must be ${AttributeCategory.Card}
-// |
-// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// cardAttributeDefinitionJsonV400,
-// cardAttributeDefinitionResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCard, apiTagCardAttribute, apiTagAttribute),
-// Some(List(canCreateCardAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val createOrUpdateCardAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "card" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AttributeDefinitionJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)"
-// attributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// AttributeType.withName(postedData.`type`)
-// }
-// failMsg =
-// s"$InvalidJsonFormat The `Category` field can only accept the following field: " +
-// s"${AttributeCategory.Card}"
-// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AttributeCategory.withName(postedData.category)
-// }
-// (attributeDefinition, callContext) <-
-// createOrUpdateAttributeDefinition(
-// bankId,
-// postedData.name,
-// category,
-// attributeType,
-// postedData.description,
-// postedData.alias,
-// postedData.can_be_seen_on_views,
-// postedData.is_active,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionJson(attributeDefinition),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteTransactionAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteTransactionAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction",
-// "Delete Transaction Attribute Definition",
-// s""" Delete Transaction Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canDeleteTransactionAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteTransactionAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(
-// AttributeCategory.Transaction.toString
-// ),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomerAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteCustomerAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/customer",
-// "Delete Customer Attribute Definition",
-// s""" Delete Customer Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(List(canDeleteCustomerAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteCustomerAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "customer" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(AttributeCategory.Customer.toString),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAccountAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteAccountAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/account",
-// "Delete Account Attribute Definition",
-// s""" Delete Account Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute),
-// Some(List(canDeleteAccountAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteAccountAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "account" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(AttributeCategory.Account.toString),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteProductAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteProductAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/product",
-// "Delete Product Attribute Definition",
-// s""" Delete Product Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canDeleteProductAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteProductAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "product" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(AttributeCategory.Product.toString),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCardAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(deleteCardAttributeDefinition),
-// "DELETE",
-// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/card",
-// "Delete Card Attribute Definition",
-// s""" Delete Card Attribute Definition by ATTRIBUTE_DEFINITION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCard, apiTagCardAttribute, apiTagAttribute),
-// Some(List(canDeleteCardAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val deleteCardAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: attributeDefinitionId :: "card" :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteAttributeDefinition(
-// attributeDefinitionId,
-// AttributeCategory.withName(AttributeCategory.Card.toString),
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProductAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getProductAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/product",
-// "Get Product Attribute Definition",
-// s""" Get Product Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// productAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute),
-// Some(List(canGetProductAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getProductAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "product" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(AttributeCategory.Product.toString),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getCustomerAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/customer",
-// "Get Customer Attribute Definition",
-// s""" Get Customer Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute),
-// Some(List(canGetCustomerAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getCustomerAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "customer" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(AttributeCategory.Customer.toString),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getAccountAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/account",
-// "Get Account Attribute Definition",
-// s""" Get Account Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// accountAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute),
-// Some(List(canGetAccountAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getAccountAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "account" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(AttributeCategory.Account.toString),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getTransactionAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/transaction",
-// "Get Transaction Attribute Definition",
-// s""" Get Transaction Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// transactionAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute),
-// Some(List(canGetTransactionAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getTransactionAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "transaction" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(
-// AttributeCategory.Transaction.toString
-// ),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(
-// attributeDefinitions
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCardAttributeDefinition,
-// implementedInApiVersion,
-// nameOf(getCardAttributeDefinition),
-// "GET",
-// "/banks/BANK_ID/attribute-definitions/card",
-// "Get Card Attribute Definition",
-// s""" Get Card Attribute Definition
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// cardAttributeDefinitionsResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCard, apiTagCardAttribute, apiTagAttribute),
-// Some(List(canGetCardAttributeDefinitionAtOneBank))
-// )
-//
-// lazy val getCardAttributeDefinition: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "attribute-definitions" :: "card" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributeDefinitions, callContext) <- getAttributeDefinition(
-// AttributeCategory.withName(AttributeCategory.Card.toString),
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteUserCustomerLink,
-// implementedInApiVersion,
-// nameOf(deleteUserCustomerLink),
-// "DELETE",
-// "/banks/BANK_ID/user_customer_links/USER_CUSTOMER_LINK_ID",
-// "Delete User Customer Link",
-// s""" Delete User Customer Link by USER_CUSTOMER_LINK_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canDeleteUserCustomerLink))
-// )
-//
-// lazy val deleteUserCustomerLink: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user_customer_links" :: userCustomerLinkId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- UserCustomerLinkNewStyle
-// .deleteUserCustomerLink(
-// userCustomerLinkId,
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserCustomerLinksByUserId,
-// implementedInApiVersion,
-// nameOf(getUserCustomerLinksByUserId),
-// "GET",
-// "/banks/BANK_ID/user_customer_links/users/USER_ID",
-// "Get User Customer Links by User",
-// s""" Get User Customer Links by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userCustomerLinksJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetUserCustomerLink))
-// )
-//
-// lazy val getUserCustomerLinksByUserId: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user_customer_links" :: "users" :: userId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle
-// .getUserCustomerLinksByUserId(
-// userId,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUserCustomerLinks,
-// implementedInApiVersion,
-// "createUserCustomerLinks",
-// "POST",
-// "/banks/BANK_ID/user_customer_links",
-// "Create User Customer Link",
-// s"""Link a User to a Customer
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// createUserCustomerLinkJson,
-// userCustomerLinkJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// CustomerAlreadyExistsForUser,
-// CreateUserCustomerLinksError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canCreateUserCustomerLinkAtAnyBank, canCreateUserCustomerLink))
-// )
-//
-// lazy val createUserCustomerLinks: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user_customer_links" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.tryons(
-// s"$InvalidBankIdFormat",
-// 400,
-// cc.callContext
-// ) {
-// assert(isValidID(bankId.value))
-// }
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $CreateUserCustomerLinkJson ",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[CreateUserCustomerLinkJson]
-// }
-// user <- Users.users.vend.getUserByUserIdFuture(
-// postedData.user_id
-// ) map { x =>
-// unboxFullOrFail(x, cc.callContext, UserNotFoundByUserId, 404)
-// }
-// _ <- booleanToFuture(
-// "Field customer_id is not defined in the posted json!",
-// 400,
-// cc.callContext
-// ) {
-// postedData.customer_id.nonEmpty
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// postedData.customer_id,
-// cc.callContext
-// )
-// _ <- booleanToFuture(
-// s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to matches BANK_ID(${bankId.value}) in URL",
-// 400,
-// callContext
-// ) {
-// customer.bankId == bankId.value
-// }
-// _ <- booleanToFuture(CustomerAlreadyExistsForUser, 400, callContext) {
-// UserCustomerLink.userCustomerLink.vend
-// .getUserCustomerLink(postedData.user_id, postedData.customer_id)
-// .isEmpty == true
-// }
-// userCustomerLink <- Future {
-// UserCustomerLink.userCustomerLink.vend.createUserCustomerLink(
-// postedData.user_id,
-// postedData.customer_id,
-// new Date(),
-// true
-// )
-// } map { x =>
-// unboxFullOrFail(x, callContext, CreateUserCustomerLinksError, 400)
-// }
-// } yield {
-// (
-// code.api.v2_0_0.JSONFactory200
-// .createUserCustomerLinkJSON(userCustomerLink),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserCustomerLinksByCustomerId,
-// implementedInApiVersion,
-// nameOf(getUserCustomerLinksByCustomerId),
-// "GET",
-// "/banks/BANK_ID/user_customer_links/customers/CUSTOMER_ID",
-// "Get User Customer Links by Customer",
-// s""" Get User Customer Links by CUSTOMER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userCustomerLinksJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetUserCustomerLink))
-// )
-//
-// lazy val getUserCustomerLinksByCustomerId: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "user_customer_links" :: "customers" :: customerId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (userCustomerLinks, callContext) <- getUserCustomerLinks(
-// customerId,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCorrelatedUsersInfoByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCorrelatedUsersInfoByCustomerId),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/correlated-users",
-// "Get Correlated User Info by Customer",
-// s"""Get Correlated User Info by CUSTOMER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAndUsersWithAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCorrelatedUsersInfoAtAnyBank, canGetCorrelatedUsersInfo))
-// )
-//
-// lazy val getCorrelatedUsersInfoByCustomerId: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "customers" :: customerId :: "correlated-users" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, cc.callContext)
-// (userCustomerLinks, callContext) <- getUserCustomerLinks(
-// customerId,
-// callContext
-// )
-// (users, callContext) <- NewStyle.function.getUsersByUserIds(
-// userCustomerLinks.map(_.userId),
-// callContext
-// )
-// (attributes, callContext) <- NewStyle.function
-// .getUserAttributesByUsers(
-// userCustomerLinks.map(_.userId),
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerAdUsersWithAttributesJson(
-// customer,
-// users,
-// attributes
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyCorrelatedEntities,
-// implementedInApiVersion,
-// nameOf(getMyCorrelatedEntities),
-// "GET",
-// "/my/correlated-entities",
-// "Get Correlated Entities for the current User",
-// s"""Correlated Entities are users and customers linked to the currently authenticated user via User-Customer-Links
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// correlatedUsersResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer)
-// )
-//
-// private def getCorrelatedUsersInfo(
-// userCustomerLink: UserCustomerLink,
-// callContext: Option[CallContext]
-// ) = for {
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// userCustomerLink.customerId,
-// callContext
-// )
-// (userCustomerLinks, callContext) <- getUserCustomerLinks(
-// userCustomerLink.customerId,
-// callContext
-// )
-// (users, callContext) <- NewStyle.function.getUsersByUserIds(
-// userCustomerLinks.map(_.userId),
-// callContext
-// )
-// (attributes, callContext) <- NewStyle.function.getUserAttributesByUsers(
-// userCustomerLinks.map(_.userId),
-// callContext
-// )
-// } yield {
-// (customer, users, attributes, callContext)
-// }
-//
-// lazy val getMyCorrelatedEntities: OBPEndpoint = {
-// case "my" :: "correlated-entities" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle
-// .getUserCustomerLinksByUserId(
-// u.userId,
-// callContext
-// )
-// correlatedUserInfoList <- Future.sequence(
-// userCustomerLinks.map(getCorrelatedUsersInfo(_, callContext))
-// )
-// } yield {
-// (
-// CorrelatedEntities(
-// correlatedUserInfoList.map(correlatedUserInfo =>
-// JSONFactory400.createCustomerAdUsersWithAttributesJson(
-// correlatedUserInfo._1,
-// correlatedUserInfo._2,
-// correlatedUserInfo._3
-// )
-// )
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomer,
-// implementedInApiVersion,
-// nameOf(createCustomer),
-// "POST",
-// "/banks/BANK_ID/customers",
-// "Create Customer",
-// s"""
-// |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.
-// |Dates need to be in the format 2013-01-21T23:08:00Z
-// |
-// |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// postCustomerJsonV310,
-// customerJsonV310,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateConsumerError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson),
-// Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))
-// )
-// lazy val createCustomer: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "customers" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 ",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostCustomerJsonV310]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// InvalidJsonContent + s" The field dependants(${postedData.dependants}) not equal the length(${postedData.dob_of_dependants.length}) of dob_of_dependants array",
-// 400,
-// cc.callContext
-// ) {
-// postedData.dependants == postedData.dob_of_dependants.length
-// }
-// (customer, callContext) <- NewStyle.function.createCustomer(
-// bankId,
-// postedData.legal_name,
-// postedData.mobile_phone_number,
-// postedData.email,
-// CustomerFaceImage(
-// postedData.face_image.date,
-// postedData.face_image.url
-// ),
-// postedData.date_of_birth,
-// postedData.relationship_status,
-// postedData.dependants,
-// postedData.dob_of_dependants,
-// postedData.highest_education_attained,
-// postedData.employment_status,
-// postedData.kyc_status,
-// postedData.last_ok_date,
-// Option(
-// CreditRating(
-// postedData.credit_rating.rating,
-// postedData.credit_rating.source
-// )
-// ),
-// Option(
-// CreditLimit(
-// postedData.credit_limit.currency,
-// postedData.credit_limit.amount
-// )
-// ),
-// postedData.title,
-// postedData.branch_id,
-// postedData.name_suffix,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory310.createCustomerJson(customer),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountsMinimalByCustomerId,
-// implementedInApiVersion,
-// nameOf(getAccountsMinimalByCustomerId),
-// "GET",
-// "/customers/CUSTOMER_ID/accounts-minimal",
-// "Get Accounts Minimal for a Customer",
-// s"""Get Accounts Minimal by CUSTOMER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// accountsMinimalJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// CustomerNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canGetAccountsMinimalForCustomerAtOneBank, canGetAccountsMinimalForCustomerAtAnyBank))
-// )
-//
-// lazy val getAccountsMinimalByCustomerId: OBPEndpoint = {
-// case "customers" :: customerId :: "accounts-minimal" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (customer, callContext) <- getCustomerByCustomerId(
-// customerId,
-// callContext
-// )
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(customer.bankId, u.userId, canGetAccountsMinimalForCustomerAtOneBank :: canGetAccountsMinimalForCustomerAtAnyBank :: Nil, callContext)
-// (userCustomerLinks, callContext) <- getUserCustomerLinks(
-// customerId,
-// callContext
-// )
-// (users, callContext) <- getUsersByUserIds(
-// userCustomerLinks.map(_.userId),
-// callContext
-// )
-// } yield {
-// val accountAccess =
-// for (user <- users)
-// yield Views.views.vend.privateViewsUserCanAccess(user)._2
-// (
-// JSONFactory400.createAccountsMinimalJson400(
-// accountAccess.flatten
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteTransactionCascade,
-// implementedInApiVersion,
-// nameOf(deleteTransactionCascade),
-// "DELETE",
-// "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID",
-// "Delete Transaction Cascade",
-// s"""Delete a Transaction Cascade specified by TRANSACTION_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagTransaction),
-// Some(List(canDeleteTransactionCascade))
-// )
-//
-// lazy val deleteTransactionCascade: OBPEndpoint = {
-// case "management" :: "cascading" :: "banks" :: BankId(
-// bankId
-// ) :: "accounts" :: AccountId(accountId) ::
-// "transactions" :: TransactionId(
-// transactionId
-// ) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getTransaction(
-// bankId,
-// accountId,
-// transactionId,
-// cc.callContext
-// )
-// _ <- Future(
-// DeleteTransactionCascade.atomicDelete(
-// bankId,
-// accountId,
-// transactionId
-// )
-// )
-// } yield {
-// (Full(true), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAccountCascade,
-// implementedInApiVersion,
-// nameOf(deleteAccountCascade),
-// "DELETE",
-// "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID",
-// "Delete Account Cascade",
-// s"""Delete an Account Cascade specified by ACCOUNT_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canDeleteAccountCascade))
-// )
-//
-// lazy val deleteAccountCascade: OBPEndpoint = {
-// case "management" :: "cascading" :: "banks" :: BankId(
-// bankId
-// ) :: "accounts" :: AccountId(accountId) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// result <- Future(DeleteAccountCascade.atomicDelete(bankId, accountId))
-// } yield {
-// if (result.getOrElse(false))
-// (Full(true), HttpCode.`200`(cc))
-// else
-// (Full(false), HttpCode.`404`(cc))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankCascade,
-// implementedInApiVersion,
-// nameOf(deleteBankCascade),
-// "DELETE",
-// "/management/cascading/banks/BANK_ID",
-// "Delete Bank Cascade",
-// s"""Delete a Bank Cascade specified by BANK_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canDeleteBankCascade))
-// )
-//
-// lazy val deleteBankCascade: OBPEndpoint = {
-// case "management" :: "cascading" :: "banks" :: BankId(
-// bankId
-// ) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(DeleteBankCascade.atomicDelete(bankId))
-// } yield {
-// (Full(true), HttpCode.`200`(cc))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteProductCascade,
-// implementedInApiVersion,
-// nameOf(deleteProductCascade),
-// "DELETE",
-// "/management/cascading/banks/BANK_ID/products/PRODUCT_CODE",
-// "Delete Product Cascade",
-// s"""Delete a Product Cascade specified by PRODUCT_CODE.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canDeleteProductCascade))
-// )
-//
-// lazy val deleteProductCascade: OBPEndpoint = {
-// case "management" :: "cascading" :: "banks" :: BankId(
-// bankId
-// ) :: "products" :: ProductCode(code) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getProduct(
-// bankId,
-// code,
-// Some(cc)
-// )
-// _ <- Future(DeleteProductCascade.atomicDelete(bankId, code))
-// } yield {
-// (Full(true), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomerCascade,
-// implementedInApiVersion,
-// nameOf(deleteCustomerCascade),
-// "DELETE",
-// "/management/cascading/banks/BANK_ID/customers/CUSTOMER_ID",
-// "Delete Customer Cascade",
-// s"""Delete a Customer Cascade specified by CUSTOMER_ID.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canDeleteCustomerCascade))
-// )
-//
-// lazy val deleteCustomerCascade: OBPEndpoint = {
-// case "management" :: "cascading" :: "banks" :: BankId(
-// bankId
-// ) :: "customers" :: CustomerId(customerId) :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(
-// customerId.value,
-// Some(cc)
-// )
-// _ <- Future(DeleteCustomerCascade.atomicDelete(customerId))
-// } yield {
-// (Full(true), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createExplicitCounterparty,
-// implementedInApiVersion,
-// "createCounterparty",
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties",
-// "Create Counterparty (Explicit)",
-// s"""This endpoint creates an (Explicit) Counterparty for an Account.
-// |
-// |For an introduction to Counterparties in OBP see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// postCounterpartyJson400,
-// counterpartyWithMetadataJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// InvalidISOCurrencyCode,
-// ViewNotFound,
-// CounterpartyAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount)
-// )
-//
-// lazy val createExplicitCounterparty: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// InvalidAccountIdFormat,
-// cc = callContext
-// ) { isValidID(accountId.value) }
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) {
-// isValidID(bankId.value)
-// }
-// postJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostCounterpartyJSON",
-// 400,
-// callContext
-// ) {
-// json.extract[PostCounterpartyJson400]
-// }
-//
-// _ <- Helper.booleanToFuture(
-// s"$NoViewPermission can_add_counterparty. Please use a view with that permission or add the permission to this view.",
-// 403,
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_ADD_COUNTERPARTY)
-// }
-//
-// (counterparty, callContext) <- Connector.connector.vend
-// .checkCounterpartyExists(
-// postJson.name,
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// callContext
-// )
-//
-// _ <- Helper.booleanToFuture(
-// CounterpartyAlreadyExists.replace(
-// "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.",
-// s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)"
-// ),
-// cc = callContext
-// ) {
-// counterparty.isEmpty
-// }
-// _ <- booleanToFuture(
-// s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}",
-// cc = callContext
-// ) {
-// postJson.description.length <= 36
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'",
-// cc = callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(postJson.currency)
-// }
-//
-// // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account.
-// (_, callContext) <-
-// if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// ) && postJson.other_account_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// )
-// ) {
-// for {
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(postJson.other_bank_routing_address),
-// Some(cc)
-// )
-// (account, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// BankId(postJson.other_bank_routing_address),
-// AccountId(postJson.other_account_routing_address),
-// callContext
-// )
-//
-// } yield {
-// (account, callContext)
-// }
-// } else if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// ) && postJson.other_account_secondary_routing_scheme
-// .equalsIgnoreCase("OBP")
-// ) {
-// for {
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(postJson.other_bank_routing_address),
-// Some(cc)
-// )
-// (account, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// BankId(postJson.other_bank_routing_address),
-// AccountId(
-// postJson.other_account_secondary_routing_address
-// ),
-// callContext
-// )
-//
-// } yield {
-// (account, callContext)
-// }
-// } else if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "ACCOUNT_NUMBER"
-// ) || postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "ACCOUNT_NO"
-// )
-// ) {
-// for {
-// bankIdOption <- Future.successful(
-// if (postJson.other_bank_routing_address.isEmpty) None
-// else Some(postJson.other_bank_routing_address)
-// )
-// (account, callContext) <- NewStyle.function
-// .getBankAccountByNumber(
-// bankIdOption.map(BankId(_)),
-// postJson.other_bank_routing_address,
-// callContext
-// )
-// } yield {
-// (account, callContext)
-// }
-// } else
-// Future { (Full(()), Some(cc)) }
-//
-// otherAccountRoutingSchemeOBPFormat =
-// if (
-// postJson.other_account_routing_scheme.equalsIgnoreCase(
-// "AccountNo"
-// )
-// ) "ACCOUNT_NUMBER"
-// else
-// StringHelpers
-// .snakify(postJson.other_account_routing_scheme)
-// .toUpperCase
-//
-// (counterparty, callContext) <- NewStyle.function.createCounterparty(
-// name = postJson.name,
-// description = postJson.description,
-// currency = postJson.currency,
-// createdByUserId = u.userId,
-// thisBankId = bankId.value,
-// thisAccountId = accountId.value,
-// thisViewId = viewId.value,
-// otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat,
-// otherAccountRoutingAddress =
-// postJson.other_account_routing_address,
-// otherAccountSecondaryRoutingScheme = StringHelpers
-// .snakify(postJson.other_account_secondary_routing_scheme)
-// .toUpperCase,
-// otherAccountSecondaryRoutingAddress =
-// postJson.other_account_secondary_routing_address,
-// otherBankRoutingScheme = StringHelpers
-// .snakify(postJson.other_bank_routing_scheme)
-// .toUpperCase,
-// otherBankRoutingAddress = postJson.other_bank_routing_address,
-// otherBranchRoutingScheme = StringHelpers
-// .snakify(postJson.other_branch_routing_scheme)
-// .toUpperCase,
-// otherBranchRoutingAddress = postJson.other_branch_routing_address,
-// isBeneficiary = postJson.is_beneficiary,
-// bespoke = postJson.bespoke.map(bespoke =>
-// CounterpartyBespoke(bespoke.key, bespoke.value)
-// ),
-// callContext
-// )
-//
-// (counterpartyMetadata, callContext) <- NewStyle.function
-// .getOrCreateMetadata(
-// bankId,
-// accountId,
-// counterparty.counterpartyId,
-// postJson.name,
-// callContext
-// )
-//
-// } yield {
-// (
-// JSONFactory400.createCounterpartyWithMetadataJson400(
-// counterparty,
-// counterpartyMetadata
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteExplicitCounterparty,
-// implementedInApiVersion,
-// nameOf(deleteExplicitCounterparty),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID",
-// "Delete Counterparty (Explicit)",
-// s"""This endpoint deletes the Counterparty on the Account / View specified by the COUNTERPARTY_ID.
-// |It also deletes any related Counterparty Metadata.
-// |
-// |The User calling this endpoint must have access to the View specified in the URL and that View must have the permission `can_delete_counterparty`.
-// |
-// |For a general introduction to Counterparties in OBP see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// | |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount)
-// )
-//
-// lazy val deleteExplicitCounterparty: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId(
-// counterpartyId
-// ) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// InvalidAccountIdFormat,
-// cc = callContext
-// ) { isValidID(accountId.value) }
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) {
-// isValidID(bankId.value)
-// }
-//
-// _ <- Helper.booleanToFuture(
-// s"$NoViewPermission can_delete_counterparty. Please use a view with that permission or add the permission to this view.",
-// 403,
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_DELETE_COUNTERPARTY)
-// }
-//
-// (counterparty, callContext) <- NewStyle.function
-// .deleteCounterpartyByCounterpartyId(counterpartyId, callContext)
-//
-// (counterpartyMetadata, callContext) <- NewStyle.function
-// .deleteMetadata(
-// bankId,
-// accountId,
-// counterpartyId.value,
-// callContext
-// )
-//
-// } yield {
-// (Full(counterparty), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCounterpartyForAnyAccount,
-// implementedInApiVersion,
-// nameOf(deleteCounterpartyForAnyAccount),
-// "DELETE",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID",
-// "Delete Counterparty for any account (Explicit)",
-// s"""This is a management endpoint that enables the deletion of any specified Counterparty along with any related Metadata of that Counterparty.
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankAccountNotFound,
-// $BankNotFound,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount),
-// Some(List(canDeleteCounterparty, canDeleteCounterpartyAtAnyBank))
-// )
-//
-// lazy val deleteCounterpartyForAnyAccount: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId(
-// counterpartyId
-// ) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount
-//
-// _ <- Helper.booleanToFuture(
-// InvalidAccountIdFormat,
-// cc = callContext
-// ) { isValidID(accountId.value) }
-//
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) {
-// isValidID(bankId.value)
-// }
-//
-// (counterparty, callContext) <- NewStyle.function
-// .deleteCounterpartyByCounterpartyId(counterpartyId, callContext)
-//
-// (counterpartyMetadata, callContext) <- NewStyle.function
-// .deleteMetadata(
-// bankId,
-// accountId,
-// counterpartyId.value,
-// callContext
-// )
-//
-// } yield {
-// (Full(counterparty), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCounterpartyForAnyAccount,
-// implementedInApiVersion,
-// "createCounterpartyForAnyAccount",
-// "POST",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties",
-// "Create Counterparty for any account (Explicit)",
-// s"""This is a management endpoint that allows the creation of a Counterparty on any Account.
-// |
-// |For an introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// postCounterpartyJson400,
-// counterpartyWithMetadataJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// AccountNotFound,
-// InvalidJsonFormat,
-// InvalidISOCurrencyCode,
-// ViewNotFound,
-// CounterpartyAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount),
-// Some(List(canCreateCounterparty, canCreateCounterpartyAtAnyBank))
-// )
-//
-// lazy val createCounterpartyForAnyAccount: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount
-// postJson <- NewStyle.function.tryons(
-// InvalidJsonFormat,
-// 400,
-// callContext
-// ) {
-// json.extract[PostCounterpartyJson400]
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}",
-// cc = callContext
-// ) { postJson.description.length <= 36 }
-//
-// (counterparty, callContext) <- Connector.connector.vend
-// .checkCounterpartyExists(
-// postJson.name,
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// callContext
-// )
-//
-// _ <- Helper.booleanToFuture(
-// CounterpartyAlreadyExists.replace(
-// "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.",
-// s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)"
-// ),
-// cc = callContext
-// ) {
-// counterparty.isEmpty
-// }
-//
-// _ <- Helper.booleanToFuture(
-// s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'",
-// cc = callContext
-// ) {
-// APIUtil.isValidCurrencyISOCode(postJson.currency)
-// }
-//
-// // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account.
-// (_, callContext) <-
-// if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// ) && postJson.other_account_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// )
-// ) {
-// for {
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(postJson.other_bank_routing_address),
-// Some(cc)
-// )
-// (account, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// BankId(postJson.other_bank_routing_address),
-// AccountId(postJson.other_account_routing_address),
-// callContext
-// )
-//
-// } yield {
-// (account, callContext)
-// }
-// } else if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "OBP"
-// ) && postJson.other_account_secondary_routing_scheme
-// .equalsIgnoreCase("OBP")
-// ) {
-// for {
-// (_, callContext) <- NewStyle.function.getBank(
-// BankId(postJson.other_bank_routing_address),
-// Some(cc)
-// )
-// (account, callContext) <- NewStyle.function
-// .checkBankAccountExists(
-// BankId(postJson.other_bank_routing_address),
-// AccountId(
-// postJson.other_account_secondary_routing_address
-// ),
-// callContext
-// )
-//
-// } yield {
-// (account, callContext)
-// }
-// } else if (
-// postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "ACCOUNT_NUMBER"
-// ) || postJson.other_bank_routing_scheme.equalsIgnoreCase(
-// "ACCOUNT_NO"
-// )
-// ) {
-// for {
-// bankIdOption <- Future.successful(
-// if (postJson.other_bank_routing_address.isEmpty) None
-// else Some(postJson.other_bank_routing_address)
-// )
-// (account, callContext) <- NewStyle.function
-// .getBankAccountByNumber(
-// bankIdOption.map(BankId(_)),
-// postJson.other_bank_routing_address,
-// callContext
-// )
-// } yield {
-// (account, callContext)
-// }
-// } else
-// Future { (Full(()), Some(cc)) }
-//
-// otherAccountRoutingSchemeOBPFormat =
-// if (
-// postJson.other_account_routing_scheme.equalsIgnoreCase(
-// "AccountNo"
-// )
-// ) "ACCOUNT_NUMBER"
-// else
-// StringHelpers
-// .snakify(postJson.other_account_routing_scheme)
-// .toUpperCase
-//
-// (counterparty, callContext) <- NewStyle.function.createCounterparty(
-// name = postJson.name,
-// description = postJson.description,
-// currency = postJson.currency,
-// createdByUserId = u.userId,
-// thisBankId = bankId.value,
-// thisAccountId = accountId.value,
-// thisViewId = Constant.SYSTEM_OWNER_VIEW_ID,
-// otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat,
-// otherAccountRoutingAddress =
-// postJson.other_account_routing_address,
-// otherAccountSecondaryRoutingScheme = StringHelpers
-// .snakify(postJson.other_account_secondary_routing_scheme)
-// .toUpperCase,
-// otherAccountSecondaryRoutingAddress =
-// postJson.other_account_secondary_routing_address,
-// otherBankRoutingScheme = StringHelpers
-// .snakify(postJson.other_bank_routing_scheme)
-// .toUpperCase,
-// otherBankRoutingAddress = postJson.other_bank_routing_address,
-// otherBranchRoutingScheme = StringHelpers
-// .snakify(postJson.other_branch_routing_scheme)
-// .toUpperCase,
-// otherBranchRoutingAddress = postJson.other_branch_routing_address,
-// isBeneficiary = postJson.is_beneficiary,
-// bespoke = postJson.bespoke.map(bespoke =>
-// CounterpartyBespoke(bespoke.key, bespoke.value)
-// ),
-// callContext
-// )
-//
-// (counterpartyMetadata, callContext) <- NewStyle.function
-// .getOrCreateMetadata(
-// bankId,
-// accountId,
-// counterparty.counterpartyId,
-// postJson.name,
-// callContext
-// )
-//
-// } yield {
-// (
-// JSONFactory400.createCounterpartyWithMetadataJson400(
-// counterparty,
-// counterpartyMetadata
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getExplicitCounterpartiesForAccount,
-// implementedInApiVersion,
-// "getExplicitCounterpartiesForAccount",
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties",
-// "Get Counterparties (Explicit)",
-// s"""Get the Counterparties that have been explicitly created on the specified Account / View.
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// counterpartiesJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// ViewNotFound,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount)
-// )
-//
-// lazy val getExplicitCounterpartiesForAccount: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg = s"${NoViewPermission}can_get_counterparty",
-// 403,
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY)
-// }
-// (counterparties, callContext) <- NewStyle.function.getCounterparties(
-// bankId,
-// accountId,
-// viewId,
-// callContext
-// )
-// // Here we need create the metadata for all the explicit counterparties. maybe show them in json response.
-// // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata.
-// _ <- Helper.booleanToFuture(
-// CreateOrUpdateCounterpartyMetadataError,
-// 400,
-// cc = callContext
-// ) {
-// {
-// for {
-// counterparty <- counterparties
-// } yield {
-// Counterparties.counterparties.vend.getOrCreateMetadata(
-// bankId,
-// accountId,
-// counterparty.counterpartyId,
-// counterparty.name
-// ) match {
-// case Full(_) => true
-// case _ => false
-// }
-// }
-// }.forall(_ == true)
-// }
-// } yield {
-// val counterpartiesJson =
-// JSONFactory400.createCounterpartiesJson400(counterparties)
-// (counterpartiesJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartiesForAnyAccount,
-// implementedInApiVersion,
-// nameOf(getCounterpartiesForAnyAccount),
-// "GET",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties",
-// "Get Counterparties for any account (Explicit)",
-// s"""This is a management endpoint that gets the Counterparties that have been explicitly created for an Account / View.
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// counterpartiesJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount),
-// Some(List(canGetCounterparties, canGetCounterpartiesAtAnyBank))
-// )
-//
-// lazy val getCounterpartiesForAnyAccount: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount
-// (counterparties, callContext) <- NewStyle.function.getCounterparties(
-// bankId,
-// accountId,
-// viewId,
-// callContext
-// )
-// // Here we need create the metadata for all the explicit counterparties. maybe show them in json response.
-// // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata.
-// _ <- Helper.booleanToFuture(
-// CreateOrUpdateCounterpartyMetadataError,
-// 400,
-// cc = callContext
-// ) {
-// {
-// for {
-// counterparty <- counterparties
-// } yield {
-// Counterparties.counterparties.vend.getOrCreateMetadata(
-// bankId,
-// accountId,
-// counterparty.counterpartyId,
-// counterparty.name
-// ) match {
-// case Full(_) => true
-// case _ => false
-// }
-// }
-// }.forall(_ == true)
-// }
-// } yield {
-// val counterpartiesJson =
-// JSONFactory400.createCounterpartiesJson400(counterparties)
-// (counterpartiesJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getExplicitCounterpartyById,
-// implementedInApiVersion,
-// "getExplicitCounterpartyById",
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID",
-// "Get Counterparty by Id (Explicit)",
-// s"""This endpoint returns a single Counterparty on an Account View specified by its COUNTERPARTY_ID:
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// counterpartyWithMetadataJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(
-// apiTagCounterparty,
-// apiTagPSD2PIS,
-// apiTagPsd2,
-// apiTagCounterpartyMetaData
-// )
-// )
-//
-// lazy val getExplicitCounterpartyById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId(
-// counterpartyId
-// ) :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// _ <- Helper.booleanToFuture(
-// failMsg = s"${NoViewPermission}can_get_counterparty",
-// 403,
-// cc = callContext
-// ) {
-// view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY)
-// }
-// (counterparty, callContext) <- NewStyle.function
-// .getCounterpartyByCounterpartyId(counterpartyId, callContext)
-// counterpartyMetadata <- NewStyle.function.getMetadata(
-// bankId,
-// accountId,
-// counterpartyId.value,
-// callContext
-// )
-// } yield {
-// val counterpartyJson =
-// JSONFactory400.createCounterpartyWithMetadataJson400(
-// counterparty,
-// counterpartyMetadata
-// )
-// (counterpartyJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartyByNameForAnyAccount,
-// implementedInApiVersion,
-// nameOf(getCounterpartyByNameForAnyAccount),
-// "GET",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparty-names/COUNTERPARTY_NAME",
-// "Get Counterparty by name for any account (Explicit) ",
-// s"""This is a management endpoint that allows the retrieval of any Counterparty on an Account / View by its Name.
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// counterpartyWithMetadataJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// ViewNotFound,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount),
-// Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty))
-// )
-//
-// lazy val getCounterpartyByNameForAnyAccount: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(
-// viewId
-// ) :: "counterparty-names" :: counterpartyName :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount
-//
-// (counterparty, callContext) <- Connector.connector.vend
-// .checkCounterpartyExists(
-// counterpartyName,
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// callContext
-// )
-//
-// counterparty <- NewStyle.function.tryons(
-// CounterpartyNotFound.replace(
-// "The BANK_ID / ACCOUNT_ID specified does not exist on this server.",
-// s"COUNTERPARTY_NAME(${counterpartyName}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)"
-// ),
-// 400,
-// callContext
-// ) {
-// counterparty.head
-// }
-//
-// (counterpartyMetadata, callContext) <- NewStyle.function
-// .getOrCreateMetadata(
-// bankId,
-// accountId,
-// counterparty.counterpartyId,
-// counterparty.name,
-// callContext
-// )
-//
-// } yield {
-// (
-// JSONFactory400.createCounterpartyWithMetadataJson400(
-// counterparty,
-// counterpartyMetadata
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartyByIdForAnyAccount,
-// implementedInApiVersion,
-// nameOf(getCounterpartyByIdForAnyAccount),
-// "GET",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID",
-// "Get Counterparty by Id for any account (Explicit)",
-// s"""This is a management endpoint that gets information about any single explicitly created Counterparty on an Account / View specified by its COUNTERPARTY_ID",
-// |
-// |For a general introduction to Counterparties in OBP, see ${Glossary
-// .getGlossaryItemLink("Counterparties")}
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// counterpartyWithMetadataJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// ViewNotFound,
-// UnknownError
-// ),
-// List(apiTagCounterparty, apiTagAccount),
-// Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty))
-// )
-//
-// lazy val getCounterpartyByIdForAnyAccount: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId(
-// counterpartyId
-// ) :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, callContext) <- SS.userBankAccount
-// (counterparty, callContext) <- NewStyle.function
-// .getCounterpartyByCounterpartyId(counterpartyId, callContext)
-// counterpartyMetadata <- NewStyle.function.getMetadata(
-// bankId,
-// accountId,
-// counterpartyId.value,
-// callContext
-// )
-// } yield {
-// val counterpartyJson =
-// JSONFactory400.createCounterpartyWithMetadataJson400(
-// counterparty,
-// counterpartyMetadata
-// )
-// (counterpartyJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// addConsentUser,
-// implementedInApiVersion,
-// nameOf(addConsentUser),
-// "PUT",
-// "/banks/BANK_ID/consents/CONSENT_ID/user-update-request",
-// "Add User to a Consent",
-// s"""
-// |
-// |
-// |This endpoint is used to add the User of Consent.
-// |
-// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted
-// .mkString(", ")}.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PutConsentUserJsonV400(user_id = "ed7a7c01-db37-45cc-ba12-0ae8891c195c"),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt =
-// "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "AUTHORISED"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// $BankNotFound,
-// ConsentUserAlreadyAdded,
-// InvalidJsonFormat,
-// ConsentNotFound,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: Nil
-// )
-//
-// lazy val addConsentUser: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "consents" :: consentId :: "user-update-request" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- SS.user
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PutConsentUserJsonV400 "
-// putJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutConsentUserJsonV400]
-// }
-// user <- Users.users.vend.getUserByUserIdFuture(
-// putJson.user_id
-// ) map { x =>
-// unboxFullOrFail(
-// x,
-// callContext,
-// s"$UserNotFoundByUserId Current UserId(${putJson.user_id})"
-// )
-// }
-// consent <- Future(
-// Consents.consentProvider.vend.getConsentByConsentId(consentId)
-// ) map { i =>
-// connectorEmptyResponse(i, callContext)
-// }
-// _ <- Helper.booleanToFuture(
-// ConsentUserAlreadyAdded,
-// cc = cc.callContext
-// ) {
-// Option(consent.userId).forall(
-// _.isBlank
-// ) // checks whether userId is not populated
-// }
-// consent <- Future(
-// Consents.consentProvider.vend.updateConsentUser(consentId, user)
-// ) map { i =>
-// connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (
-// ConsentJsonV310(
-// consent.consentId,
-// consent.jsonWebToken,
-// consent.status
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsentStatus,
-// implementedInApiVersion,
-// nameOf(updateConsentStatus),
-// "PUT",
-// "/banks/BANK_ID/consents/CONSENT_ID",
-// "Update Consent Status",
-// s"""
-// |
-// |
-// |This endpoint is used to update the Status of Consent.
-// |
-// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted
-// .mkString(", ")}.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PutConsentStatusJsonV400(status = "AUTHORISED"),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt =
-// "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "AUTHORISED"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: Nil
-// )
-//
-// lazy val updateConsentStatus: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "consents" :: consentId :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- SS.user
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PutConsentStatusJsonV400 "
-// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutConsentStatusJsonV400]
-// }
-// consent <- Future(
-// Consents.consentProvider.vend.getConsentByConsentId(consentId)
-// ) map { i =>
-// connectorEmptyResponse(i, callContext)
-// }
-// status = ConsentStatus.withName(consentJson.status)
-// (consent, code) <- APIUtil.getPropsAsBoolValue(
-// "consents.sca.enabled",
-// true
-// ) match {
-// case true =>
-// Future(consent, HttpCode.`202`(callContext))
-// case false =>
-// Future(
-// Consents.consentProvider.vend
-// .updateConsentStatus(consentId, status)
-// ) map { i =>
-// connectorEmptyResponse(i, callContext)
-// } map ((_, HttpCode.`200`(callContext)))
-// }
-// } yield {
-// (
-// ConsentJsonV310(
-// consent.consentId,
-// consent.jsonWebToken,
-// consent.status
-// ),
-// code
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsents,
-// implementedInApiVersion,
-// nameOf(getConsents),
-// "GET",
-// "/banks/BANK_ID/my/consents",
-// "Get Consents",
-// s"""
-// |
-// |This endpoint gets the Consents that the current User created.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)
-// )
-//
-// lazy val getConsents: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val url = cc.url
-// val limitParam = getHttpRequestUrlParam(url, "limit") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
-// case _ => 50
-// }
-// val offsetParam = getHttpRequestUrlParam(url, "offset") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
-// case _ => 0
-// }
-// for {
-// rows <- Future {
-// DoobieConsentQueries.getConsentsByUserAndBank(
-// userId = cc.userId,
-// bankId = bankId.value,
-// status = None,
-// limit = limitParam,
-// offset = offsetParam,
-// sortField = "created_date",
-// sortDirection = "desc"
-// )
-// }
-// } yield {
-// val consents = rows.map(r => ConsentJsonV400(
-// r.consentId, r.jwt.getOrElse(""), r.status,
-// r.apiStandard.getOrElse(""), r.apiVersion.getOrElse("")
-// ))
-// (ConsentsJsonV400(consents), HttpCode.`200`(cc))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// getConsentInfosByBank,
-// implementedInApiVersion,
-// nameOf(getConsentInfosByBank),
-// "GET",
-// "/banks/BANK_ID/my/consent-infos",
-// "Get My Consents Info At Bank",
-// s"""
-// |
-// |This endpoint gets the Consents that the current User created at bank.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentInfosJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)
-// )
-//
-// lazy val getConsentInfosByBank: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "my" :: "consent-infos" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consents <- Future {
-// Consents.consentProvider.vend
-// .getConsentsByUser(cc.userId)
-// .sortBy(i => (i.creationDateTime, i.apiStandard))
-// .reverse
-// }
-// } yield {
-// val consentsOfBank = Consent.filterByBankId(consents, bankId)
-// (
-// JSONFactory400.createConsentInfosJsonV400(consentsOfBank),
-// HttpCode.`200`(cc)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentInfos,
-// implementedInApiVersion,
-// nameOf(getConsentInfos),
-// "GET",
-// "/my/consent-infos",
-// "Get My Consents Info",
-// s"""
-// |
-// |This endpoint gets the Consents that the current User created.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentInfosJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)
-// )
-//
-// lazy val getConsentInfos: OBPEndpoint = {
-// case "my" :: "consent-infos" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consents <- Future {
-// Consents.consentProvider.vend
-// .getConsentsByUser(cc.userId)
-// .sortBy(i => (i.creationDateTime, i.apiStandard))
-// .reverse
-// }
-// } yield {
-// (
-// JSONFactory400.createConsentInfosJsonV400(consents),
-// HttpCode.`200`(cc)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyPersonalUserAttributes,
-// implementedInApiVersion,
-// nameOf(getMyPersonalUserAttributes),
-// "GET",
-// "/my/user/attributes",
-// "Get My Personal User Attributes",
-// s"""Get My Personal User Attributes.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// userAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagUser)
-// )
-//
-// lazy val getMyPersonalUserAttributes: OBPEndpoint = {
-// case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributes, callContext) <- NewStyle.function
-// .getPersonalUserAttributes(cc.userId, cc.callContext)
-// } yield {
-// (
-// JSONFactory400.createUserAttributesJson(attributes),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserWithAttributes,
-// implementedInApiVersion,
-// nameOf(getUserWithAttributes),
-// "GET",
-// "/users/USER_ID/attributes",
-// "Get User with Attributes by USER_ID",
-// s"""Get User Attributes for the user defined via USER_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// userWithAttributesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(canGetUsersWithAttributes :: Nil)
-// )
-//
-// lazy val getUserWithAttributes: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- NewStyle.function.getUserByUserId(
-// userId,
-// cc.callContext
-// )
-// (attributes, callContext) <- NewStyle.function.getUserAttributes(
-// user.userId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createUserWithAttributesJson(user, attributes),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createMyPersonalUserAttribute,
-// implementedInApiVersion,
-// nameOf(createMyPersonalUserAttribute),
-// "POST",
-// "/my/user/attributes",
-// "Create My Personal User Attribute",
-// s""" Create My Personal User Attribute
-// |
-// |The `type` field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// userAttributeJsonV400,
-// userAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List())
-// )
-//
-// lazy val createMyPersonalUserAttribute: OBPEndpoint = {
-// case "my" :: "user" :: "attributes" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg =
-// s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 "
-// for {
-// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[UserAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${TransactionAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// userAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// cc.callContext
-// ) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (userAttribute, callContext) <- NewStyle.function
-// .createOrUpdateUserAttribute(
-// cc.userId,
-// None,
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// true,
-// cc.callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createUserAttributeJson(userAttribute),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateMyPersonalUserAttribute,
-// implementedInApiVersion,
-// nameOf(updateMyPersonalUserAttribute),
-// "PUT",
-// "/my/user/attributes/USER_ATTRIBUTE_ID",
-// "Update My Personal User Attribute",
-// s"""Update My Personal User Attribute for current user by USER_ATTRIBUTE_ID
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// userAttributeJsonV400,
-// userAttributeResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List())
-// )
-//
-// lazy val updateMyPersonalUserAttribute: OBPEndpoint = {
-// case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributes, callContext) <- NewStyle.function
-// .getPersonalUserAttributes(cc.userId, cc.callContext)
-// failMsg = s"$UserAttributeNotFound"
-// _ <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// attributes.exists(_.userAttributeId == userAttributeId)
-// }
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 ",
-// 400,
-// callContext
-// ) {
-// json.extract[UserAttributeJsonV400]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// userAttributeType <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (userAttribute, callContext) <- NewStyle.function
-// .createOrUpdateUserAttribute(
-// cc.userId,
-// Some(userAttributeId),
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// true,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createUserAttributeJson(userAttribute),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getScannedApiVersions,
-// implementedInApiVersion,
-// nameOf(getScannedApiVersions),
-// "GET",
-// "/api/versions",
-// "Get scanned API Versions",
-// s"""Get all the scanned API Versions.""",
-// EmptyBody,
-// ListResult(
-// "scanned_api_versions",
-// List(Extraction.decompose(ApiVersion.v3_1_0))
-// ),
-// List(
-// UnknownError
-// ),
-// List(apiTagDocumentation, apiTagApi),
-// Some(Nil)
-// )
-//
-// lazy val getScannedApiVersions: OBPEndpoint = {
-// case "api" :: "versions" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// Future {
-// val versions: List[ScannedApiVersion] =
-// ApiVersion.allScannedApiVersion.asScala.toList.filter { version =>
-// version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version)
-// }
-// (
-// ListResult("scanned_api_versions", versions),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createMyApiCollection,
-// implementedInApiVersion,
-// nameOf(createMyApiCollection),
-// "POST",
-// "/my/api-collections",
-// "Create My Api Collection",
-// s"""Create Api Collection for logged in user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// postApiCollectionJson400,
-// apiCollectionJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val createMyApiCollection: OBPEndpoint = {
-// case "my" :: "api-collections" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostApiCollectionJson400]
-// }
-// apiCollection <- Future {
-// MappedApiCollectionsProvider
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// postJson.api_collection_name
-// )
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$ApiCollectionAlreadyExists Current api_collection_name(${postJson.api_collection_name}) is already existing for the log in user.",
-// cc = cc.callContext
-// ) {
-// apiCollection.isEmpty
-// }
-// (apiCollection, callContext) <- NewStyle.function.createApiCollection(
-// cc.userId,
-// postJson.api_collection_name,
-// postJson.is_sharable,
-// postJson.description.getOrElse(""),
-// Some(cc)
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionJsonV400(apiCollection),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollectionByName,
-// implementedInApiVersion,
-// nameOf(getMyApiCollectionByName),
-// "GET",
-// "/my/api-collections/name/API_COLLECTION_NAME",
-// "Get My Api Collection By Name",
-// s"""Get Api Collection By API_COLLECTION_NAME.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollectionByName: OBPEndpoint = {
-// case "my" :: "api-collections" :: "name" :: apiCollectionName :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// apiCollectionName,
-// Some(cc)
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionJsonV400(apiCollection),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollectionById,
-// implementedInApiVersion,
-// nameOf(getMyApiCollectionById),
-// "GET",
-// "/my/api-collections/API_COLLECTION_ID",
-// "Get My Api Collection By Id",
-// s"""Get Api Collection By API_COLLECTION_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollectionById: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// } yield {
-// (
-// JSONFactory400.createApiCollectionJsonV400(apiCollection),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSharableApiCollectionById,
-// implementedInApiVersion,
-// nameOf(getSharableApiCollectionById),
-// "GET",
-// "/api-collections/sharable/API_COLLECTION_ID",
-// "Get Sharable Api Collection By Id",
-// s"""Get Sharable Api Collection By Id.
-// |${userAuthenticationMessage(false)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionJson400,
-// List(
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getSharableApiCollectionById: OBPEndpoint = {
-// case "api-collections" :: "sharable" :: apiCollectionId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$ApiCollectionEndpointNotFound Current api_collection_id(${apiCollectionId}) is not sharable.",
-// cc = callContext
-// ) {
-// apiCollection.isSharable
-// }
-// } yield {
-// (
-// JSONFactory400.createApiCollectionJsonV400(apiCollection),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getApiCollectionsForUser,
-// implementedInApiVersion,
-// nameOf(getApiCollectionsForUser),
-// "GET",
-// "/users/USER_ID/api-collections",
-// "Get Api Collections for User",
-// s"""Get Api Collections for User.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionsJson400,
-// List(
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection),
-// Some(canGetApiCollectionsForUser :: Nil)
-// )
-//
-// lazy val getApiCollectionsForUser: OBPEndpoint = {
-// case "users" :: userId :: "api-collections" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.findByUserId(userId, Some(cc))
-// (apiCollections, callContext) <- NewStyle.function
-// .getApiCollectionsByUserId(userId, callContext)
-// } yield {
-// (
-// JSONFactory400.createApiCollectionsJsonV400(apiCollections),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getFeaturedApiCollections,
-// implementedInApiVersion,
-// nameOf(getFeaturedApiCollections),
-// "GET",
-// "/api-collections/featured",
-// "Get Featured Api Collections",
-// s"""Get Featured Api Collections.
-// |
-// |${userAuthenticationMessage(false)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionsJson400,
-// List(
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getFeaturedApiCollections: OBPEndpoint = {
-// case "api-collections" :: "featured" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollections, callContext) <- NewStyle.function
-// .getFeaturedApiCollections(cc.callContext)
-// } yield {
-// (
-// JSONFactory400.createApiCollectionsJsonV400(apiCollections),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollections,
-// implementedInApiVersion,
-// nameOf(getMyApiCollections),
-// "GET",
-// "/my/api-collections",
-// "Get My Api Collections",
-// s"""Get all the apiCollections for logged in user.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionsJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollections: OBPEndpoint = {
-// case "my" :: "api-collections" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val url = cc.url
-// val limitParam = getHttpRequestUrlParam(url, "limit") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
-// case _ => 50
-// }
-// val offsetParam = getHttpRequestUrlParam(url, "offset") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
-// case _ => 0
-// }
-// for {
-// (apiCollections, callContext) <- NewStyle.function
-// .getApiCollectionsByUserId(cc.userId, Some(cc))
-// } yield {
-// val paginated = apiCollections.drop(offsetParam).take(limitParam)
-// (
-// JSONFactory400.createApiCollectionsJsonV400(paginated),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyApiCollection,
-// implementedInApiVersion,
-// nameOf(deleteMyApiCollection),
-// "DELETE",
-// "/my/api-collections/API_COLLECTION_ID",
-// "Delete My Api Collection",
-// s"""Delete Api Collection By API_COLLECTION_ID
-// |
-// |${Glossary.getGlossaryItem("API Collections")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |
-// |
-// |""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val deleteMyApiCollection: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// (deleted, callContext) <- NewStyle.function.deleteApiCollectionById(
-// apiCollectionId,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createMyApiCollectionEndpoint,
-// implementedInApiVersion,
-// nameOf(createMyApiCollectionEndpoint),
-// "POST",
-// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints",
-// "Create My Api Collection Endpoint",
-// s"""Create Api Collection Endpoint.
-// |
-// |${Glossary.getGlossaryItem("API Collections")}
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// postApiCollectionEndpointJson400,
-// apiCollectionEndpointJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val createMyApiCollectionEndpoint: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostApiCollectionEndpointJson400]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})",
-// cc = Some(cc)
-// ) {
-// getAllResourceDocs
-// .find(_.operationId == postJson.operation_id.trim)
-// .isDefined
-// }
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// apiCollectionName,
-// Some(cc)
-// )
-// apiCollectionEndpoint <- Future {
-// MappedApiCollectionEndpointsProvider
-// .getApiCollectionEndpointByApiCollectionIdAndOperationId(
-// apiCollection.apiCollectionId,
-// postJson.operation_id
-// )
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_NAME($apiCollectionName) ",
-// cc = callContext
-// ) {
-// apiCollectionEndpoint.isEmpty
-// }
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .createApiCollectionEndpoint(
-// apiCollection.apiCollectionId,
-// postJson.operation_id,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointJsonV400(
-// apiCollectionEndpoint
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// createMyApiCollectionEndpointById,
-// implementedInApiVersion,
-// nameOf(createMyApiCollectionEndpointById),
-// "POST",
-// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints",
-// "Create My Api Collection Endpoint By Id",
-// s"""Create Api Collection Endpoint By Id.
-// |
-// |${Glossary.getGlossaryItem("API Collections")}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// postApiCollectionEndpointJson400,
-// apiCollectionEndpointJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val createMyApiCollectionEndpointById: OBPEndpoint = {
-// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postJson <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[PostApiCollectionEndpointJson400]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})",
-// cc = Some(cc)
-// ) {
-// getAllResourceDocs
-// .find(_.operationId == postJson.operation_id.trim)
-// .isDefined
-// }
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// apiCollectionEndpoint <- Future {
-// MappedApiCollectionEndpointsProvider
-// .getApiCollectionEndpointByApiCollectionIdAndOperationId(
-// apiCollection.apiCollectionId,
-// postJson.operation_id
-// )
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_ID($apiCollectionId) ",
-// cc = callContext
-// ) {
-// apiCollectionEndpoint.isEmpty
-// }
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .createApiCollectionEndpoint(
-// apiCollection.apiCollectionId,
-// postJson.operation_id,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointJsonV400(
-// apiCollectionEndpoint
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollectionEndpoint,
-// implementedInApiVersion,
-// nameOf(getMyApiCollectionEndpoint),
-// "GET",
-// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID",
-// "Get My Api Collection Endpoint",
-// s"""Get Api Collection Endpoint By API_COLLECTION_NAME and OPERATION_ID.
-// |
-// |${userAuthenticationMessage(false)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionEndpointJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollectionEndpoint: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// apiCollectionName,
-// Some(cc)
-// )
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .getApiCollectionEndpointByApiCollectionIdAndOperationId(
-// apiCollection.apiCollectionId,
-// operationId,
-// Some(cc)
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointJsonV400(
-// apiCollectionEndpoint
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getApiCollectionEndpoints,
-// implementedInApiVersion,
-// nameOf(getApiCollectionEndpoints),
-// "GET",
-// "/api-collections/API_COLLECTION_ID/api-collection-endpoints",
-// "Get Api Collection Endpoints",
-// s"""Get Api Collection Endpoints By API_COLLECTION_ID.
-// |
-// |${userAuthenticationMessage(false)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionEndpointsJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getApiCollectionEndpoints: OBPEndpoint = {
-// case "api-collections" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollectionEndpoints, callContext) <- NewStyle.function
-// .getApiCollectionEndpoints(apiCollectionId, Some(cc))
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointsJsonV400(
-// apiCollectionEndpoints
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollectionEndpoints,
-// implementedInApiVersion,
-// nameOf(getMyApiCollectionEndpoints),
-// "GET",
-// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints",
-// "Get My Api Collection Endpoints",
-// s"""Get Api Collection Endpoints By API_COLLECTION_NAME.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionEndpointsJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollectionEndpoints: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// apiCollectionName,
-// Some(cc)
-// )
-// (apiCollectionEndpoints, callContext) <- NewStyle.function
-// .getApiCollectionEndpoints(
-// apiCollection.apiCollectionId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointsJsonV400(
-// apiCollectionEndpoints
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyApiCollectionEndpointsById,
-// implementedInApiVersion,
-// nameOf(getMyApiCollectionEndpointsById),
-// "GET",
-// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints",
-// "Get My Api Collection Endpoints By Id",
-// s"""Get Api Collection Endpoints By API_COLLECTION_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionEndpointsJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val getMyApiCollectionEndpointsById: OBPEndpoint = {
-// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// (apiCollectionEndpoints, callContext) <- NewStyle.function
-// .getApiCollectionEndpoints(
-// apiCollection.apiCollectionId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createApiCollectionEndpointsJsonV400(
-// apiCollectionEndpoints
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyApiCollectionEndpoint,
-// implementedInApiVersion,
-// nameOf(deleteMyApiCollectionEndpoint),
-// "DELETE",
-// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID",
-// "Delete My Api Collection Endpoint",
-// s"""${Glossary.getGlossaryItem("API Collections")}
-// |
-// |
-// |Delete Api Collection Endpoint By OPERATION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val deleteMyApiCollectionEndpoint: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionByUserIdAndCollectionName(
-// cc.userId,
-// apiCollectionName,
-// Some(cc)
-// )
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .getApiCollectionEndpointByApiCollectionIdAndOperationId(
-// apiCollection.apiCollectionId,
-// operationId,
-// callContext
-// )
-// (deleted, callContext) <- NewStyle.function
-// .deleteApiCollectionEndpointById(
-// apiCollectionEndpoint.apiCollectionEndpointId,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyApiCollectionEndpointByOperationId,
-// implementedInApiVersion,
-// nameOf(deleteMyApiCollectionEndpointByOperationId),
-// "DELETE",
-// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints/OPERATION_ID",
-// "Delete My Api Collection Endpoint By Id",
-// s"""${Glossary.getGlossaryItem("API Collections")}
-// |
-// |Delete Api Collection Endpoint By OPERATION_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val deleteMyApiCollectionEndpointByOperationId: OBPEndpoint = {
-// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .getApiCollectionEndpointByApiCollectionIdAndOperationId(
-// apiCollection.apiCollectionId,
-// operationId,
-// callContext
-// )
-// (deleted, callContext) <- NewStyle.function
-// .deleteApiCollectionEndpointById(
-// apiCollectionEndpoint.apiCollectionEndpointId,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMyApiCollectionEndpointById,
-// implementedInApiVersion,
-// nameOf(deleteMyApiCollectionEndpointById),
-// "DELETE",
-// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoint-ids/API_COLLECTION_ENDPOINT_ID",
-// "Delete My Api Collection Endpoint By Id",
-// s"""${Glossary.getGlossaryItem("API Collections")}
-// |Delete Api Collection Endpoint
-// |Delete Api Collection Endpoint By Id
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val deleteMyApiCollectionEndpointById: OBPEndpoint = {
-// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoint-ids" :: apiCollectionEndpointId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollection, callContext) <- NewStyle.function
-// .getApiCollectionById(apiCollectionId, Some(cc))
-// (apiCollectionEndpoint, callContext) <- NewStyle.function
-// .getApiCollectionEndpointById(
-// apiCollectionEndpointId,
-// callContext
-// )
-// (deleted, callContext) <- NewStyle.function
-// .deleteApiCollectionEndpointById(
-// apiCollectionEndpoint.apiCollectionEndpointId,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createJsonSchemaValidation,
-// implementedInApiVersion,
-// nameOf(createJsonSchemaValidation),
-// "POST",
-// "/management/json-schema-validations/OPERATION_ID",
-// "Create a JSON Schema Validation",
-// s"""Create a JSON Schema Validation.
-// |
-// |Introduction:
-// |${Glossary.getGlossaryItemSimple("JSON Schema Validation")}
-// |
-// |To use this endpoint, please supply a valid json-schema in the request body.
-// |
-// |Note: It might take a few minutes for the newly created JSON Schema to take effect!
-// |""",
-// postOrPutJsonSchemaV400,
-// responseJsonSchema,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// Some(List(canCreateJsonSchemaValidation))
-// )
-//
-// lazy val createJsonSchemaValidation: OBPEndpoint = {
-// case "management" :: "json-schema-validations" :: operationId :: Nil JsonPost _ -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val httpBody: String = cc.httpBody.getOrElse("")
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// schemaErrors: util.Set[ValidationMessage] = JsonSchemaUtil
-// .validateSchema(httpBody)
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}",
-// cc = callContext
-// ) {
-// CommonUtil.Collections.isEmpty(schemaErrors)
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isJsonSchemaValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = OperationIdExistsError,
-// cc = callContext
-// ) {
-// !isExists
-// }
-// (validation, callContext) <- NewStyle.function
-// .createJsonSchemaValidation(
-// JsonValidation(operationId, httpBody),
-// callContext
-// )
-// } yield {
-// (validation, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateJsonSchemaValidation,
-// implementedInApiVersion,
-// nameOf(updateJsonSchemaValidation),
-// "PUT",
-// "/management/json-schema-validations/OPERATION_ID",
-// "Update a JSON Schema Validation",
-// s"""Update a JSON Schema Validation.
-// |
-// |Introduction:
-// |${Glossary.getGlossaryItemSimple("JSON Schema Validation")}
-// |
-// |To use this endpoint, please supply a valid json-schema in the request body.
-// |
-// |""",
-// postOrPutJsonSchemaV400,
-// responseJsonSchema,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// Some(List(canUpdateJsonSchemaValidation))
-// )
-//
-// lazy val updateJsonSchemaValidation: OBPEndpoint = {
-// case "management" :: "json-schema-validations" :: operationId :: Nil JsonPut _ -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val httpBody: String = cc.httpBody.getOrElse("")
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// schemaErrors = JsonSchemaUtil.validateSchema(httpBody)
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}",
-// cc = callContext
-// ) {
-// CommonUtil.Collections.isEmpty(schemaErrors)
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isJsonSchemaValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = JsonSchemaValidationNotFound,
-// cc = callContext
-// ) {
-// isExists
-// }
-// (validation, callContext) <- NewStyle.function
-// .updateJsonSchemaValidation(operationId, httpBody, callContext)
-// } yield {
-// (validation, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteJsonSchemaValidation,
-// implementedInApiVersion,
-// nameOf(deleteJsonSchemaValidation),
-// "DELETE",
-// "/management/json-schema-validations/OPERATION_ID",
-// "Delete a JSON Schema Validation",
-// s"""Delete a JSON Schema Validation by operation_id.
-// |
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// Some(List(canDeleteJsonSchemaValidation))
-// )
-//
-// lazy val deleteJsonSchemaValidation: OBPEndpoint = {
-// case "management" :: "json-schema-validations" :: operationId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// (isExists, callContext) <- NewStyle.function
-// .isJsonSchemaValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = JsonSchemaValidationNotFound,
-// cc = callContext
-// ) {
-// isExists
-// }
-//
-// (deleteResult, callContext) <- NewStyle.function
-// .deleteJsonSchemaValidation(operationId, callContext)
-// } yield {
-// (deleteResult, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getJsonSchemaValidation,
-// implementedInApiVersion,
-// nameOf(getJsonSchemaValidation),
-// "GET",
-// "/management/json-schema-validations/OPERATION_ID",
-// "Get a JSON Schema Validation",
-// s"""Get a JSON Schema Validation by operation_id.
-// |
-// |""",
-// EmptyBody,
-// responseJsonSchema,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// Some(List(canGetJsonSchemaValidation))
-// )
-//
-// lazy val getJsonSchemaValidation: OBPEndpoint = {
-// case "management" :: "json-schema-validations" :: operationId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (validation, callContext) <- NewStyle.function
-// .getJsonSchemaValidationByOperationId(operationId, cc.callContext)
-// } yield {
-// (validation, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllJsonSchemaValidations,
-// implementedInApiVersion,
-// nameOf(getAllJsonSchemaValidations),
-// "GET",
-// "/management/json-schema-validations",
-// "Get all JSON Schema Validations",
-// s"""Get all JSON Schema Validations.
-// |
-// |""",
-// EmptyBody,
-// ListResult("json_schema_validations", responseJsonSchema :: Nil),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// Some(List(canGetJsonSchemaValidation))
-// )
-//
-// lazy val getAllJsonSchemaValidations: OBPEndpoint = {
-// case ("management" |
-// "endpoints") :: "json-schema-validations" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (jsonSchemaValidations, callContext) <- NewStyle.function
-// .getJsonSchemaValidations(cc.callContext)
-// } yield {
-// (
-// ListResult("json_schema_validations", jsonSchemaValidations),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// private val jsonSchemaValidationRequiresRole: Boolean = APIUtil
-// .getPropsAsBoolValue("read_json_schema_validation_requires_role", false)
-// lazy val getAllJsonSchemaValidationsPublic = getAllJsonSchemaValidations
-//
-// staticResourceDocs += ResourceDoc(
-// getAllJsonSchemaValidationsPublic,
-// implementedInApiVersion,
-// nameOf(getAllJsonSchemaValidationsPublic),
-// "GET",
-// "/endpoints/json-schema-validations",
-// "Get all JSON Schema Validations - public",
-// s"""Get all JSON Schema Validations - public.
-// |
-// |""",
-// EmptyBody,
-// ListResult("json_schema_validations", responseJsonSchema :: Nil),
-// (if (jsonSchemaValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil)
-// ::: List(
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagJsonSchemaValidation),
-// None
-// )
-//
-// // auth type validation related endpoints
-// private val allowedAuthTypes =
-// AuthenticationType.values.filterNot(AuthenticationType.Anonymous.==)
-// staticResourceDocs += ResourceDoc(
-// createAuthenticationTypeValidation,
-// implementedInApiVersion,
-// nameOf(createAuthenticationTypeValidation),
-// "POST",
-// "/management/authentication-type-validations/OPERATION_ID",
-// "Create an Authentication Type Validation",
-// s"""Create an Authentication Type Validation.
-// |
-// |Please supply allowed authentication types.
-// |""",
-// allowedAuthTypes,
-// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// Some(List(canCreateAuthenticationTypeValidation))
-// )
-//
-// lazy val createAuthenticationTypeValidation: OBPEndpoint = {
-// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPost jArray -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// authTypes <- NewStyle.function.tryons(
-// s"$AuthenticationTypeNameIllegal Allowed Authentication Type names: ${allowedAuthTypes
-// .mkString("[", ", ", "]")}",
-// 400,
-// cc.callContext
-// ) {
-// jArray.extract[List[AuthenticationType]]
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isAuthenticationTypeValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = OperationIdExistsError,
-// cc = callContext
-// ) {
-// !isExists
-// }
-// (authenticationTypeValidation, callContext) <- NewStyle.function
-// .createAuthenticationTypeValidation(
-// JsonAuthTypeValidation(operationId, authTypes),
-// callContext
-// )
-// } yield {
-// (authenticationTypeValidation, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAuthenticationTypeValidation,
-// implementedInApiVersion,
-// nameOf(updateAuthenticationTypeValidation),
-// "PUT",
-// "/management/authentication-type-validations/OPERATION_ID",
-// "Update an Authentication Type Validation",
-// s"""Update an Authentication Type Validation.
-// |
-// |Please supply allowed authentication types.
-// |""",
-// allowedAuthTypes,
-// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// Some(List(canUpdateAuthenticationTypeValidation))
-// )
-//
-// lazy val updateAuthenticationTypeValidation: OBPEndpoint = {
-// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPut jArray -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// authTypes <- NewStyle.function.tryons(
-// s"$AuthenticationTypeNameIllegal Allowed AuthenticationType names: ${allowedAuthTypes
-// .mkString("[", ", ", "]")}",
-// 400,
-// cc.callContext
-// ) {
-// jArray.extract[List[AuthenticationType]]
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isAuthenticationTypeValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = AuthenticationTypeValidationNotFound,
-// cc = callContext
-// ) {
-// isExists
-// }
-// (authenticationTypeValidation, callContext) <- NewStyle.function
-// .updateAuthenticationTypeValidation(
-// operationId,
-// authTypes,
-// callContext
-// )
-// } yield {
-// (authenticationTypeValidation, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAuthenticationTypeValidation,
-// implementedInApiVersion,
-// nameOf(deleteAuthenticationTypeValidation),
-// "DELETE",
-// "/management/authentication-type-validations/OPERATION_ID",
-// "Delete an Authentication Type Validation",
-// s"""Delete an Authentication Type Validation by operation_id.
-// |
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// Some(List(canDeleteAuthenticationValidation))
-// )
-//
-// lazy val deleteAuthenticationTypeValidation: OBPEndpoint = {
-// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-//
-// (isExists, callContext) <- NewStyle.function
-// .isAuthenticationTypeValidationExists(operationId, callContext)
-// _ <- Helper.booleanToFuture(
-// failMsg = AuthenticationTypeValidationNotFound,
-// cc = callContext
-// ) {
-// isExists
-// }
-//
-// (deleteResult, callContext) <- NewStyle.function
-// .deleteAuthenticationTypeValidation(operationId, callContext)
-// } yield {
-// (deleteResult, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAuthenticationTypeValidation,
-// implementedInApiVersion,
-// nameOf(getAuthenticationTypeValidation),
-// "GET",
-// "/management/authentication-type-validations/OPERATION_ID",
-// "Get an Authentication Type Validation",
-// s"""Get an Authentication Type Validation by operation_id.
-// |
-// |""",
-// EmptyBody,
-// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes),
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// Some(List(canGetAuthenticationTypeValidation))
-// )
-//
-// lazy val getAuthenticationTypeValidation: OBPEndpoint = {
-// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (authenticationTypeValidation, callContext) <- NewStyle.function
-// .getAuthenticationTypeValidationByOperationId(
-// operationId,
-// cc.callContext
-// )
-// } yield {
-// (authenticationTypeValidation, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllAuthenticationTypeValidations,
-// implementedInApiVersion,
-// nameOf(getAllAuthenticationTypeValidations),
-// "GET",
-// "/management/authentication-type-validations",
-// "Get all Authentication Type Validations",
-// s"""Get all Authentication Type Validations.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "authentication_types_validations",
-// List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes))
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// Some(List(canGetAuthenticationTypeValidation))
-// )
-//
-// lazy val getAllAuthenticationTypeValidations: OBPEndpoint = {
-// case ("management" |
-// "endpoints") :: "authentication-type-validations" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (authenticationTypeValidations, callContext) <- NewStyle.function
-// .getAuthenticationTypeValidations(cc.callContext)
-// } yield {
-// (
-// ListResult(
-// "authentication_types_validations",
-// authenticationTypeValidations
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// private val authenticationTypeValidationRequiresRole: Boolean =
-// APIUtil.getPropsAsBoolValue(
-// "read_authentication_type_validation_requires_role",
-// false
-// )
-// lazy val getAllAuthenticationTypeValidationsPublic =
-// getAllAuthenticationTypeValidations
-//
-// staticResourceDocs += ResourceDoc(
-// getAllAuthenticationTypeValidationsPublic,
-// implementedInApiVersion,
-// nameOf(getAllAuthenticationTypeValidationsPublic),
-// "GET",
-// "/endpoints/authentication-type-validations",
-// "Get all Authentication Type Validations - public",
-// s"""Get all Authentication Type Validations - public.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "authentication_types_validations",
-// List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes))
-// ),
-// (if (authenticationTypeValidationRequiresRole) List($AuthenticatedUserIsRequired)
-// else Nil)
-// ::: List(
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAuthenticationTypeValidation),
-// None
-// )
-//
-// staticResourceDocs += ResourceDoc(
-// createConnectorMethod,
-// implementedInApiVersion,
-// nameOf(createConnectorMethod),
-// "POST",
-// "/management/connector-methods",
-// "Create Connector Method",
-// s"""Create an internal connector.
-// |
-// |The method_body is URL-encoded format String
-// |""",
-// jsonScalaConnectorMethod.copy(connectorMethodId = None),
-// jsonScalaConnectorMethod,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagConnectorMethod),
-// Some(List(canCreateConnectorMethod))
-// )
-//
-// lazy val createConnectorMethod: OBPEndpoint = {
-// case "management" :: "connector-methods" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// jsonConnectorMethod <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonConnectorMethod]
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .connectorMethodNameExists(
-// jsonConnectorMethod.methodName,
-// Some(cc)
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$ConnectorMethodAlreadyExists Please use a different method_name(${jsonConnectorMethod.methodName})",
-// cc = callContext
-// ) {
-// (!isExists)
-// }
-// connectorMethod = InternalConnector.createFunction(
-// jsonConnectorMethod.methodName,
-// jsonConnectorMethod.decodedMethodBody,
-// jsonConnectorMethod.programmingLang
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.head)
-// (connectorMethod, callContext) <- NewStyle.function
-// .createJsonConnectorMethod(jsonConnectorMethod, callContext)
-// } yield {
-// (connectorMethod, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConnectorMethod,
-// implementedInApiVersion,
-// nameOf(updateConnectorMethod),
-// "PUT",
-// "/management/connector-methods/CONNECTOR_METHOD_ID",
-// "Update Connector Method",
-// s"""Update an internal connector.
-// |
-// |The method_body is URL-encoded format String
-// |""",
-// jsonScalaConnectorMethodMethodBody,
-// jsonScalaConnectorMethod,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagConnectorMethod),
-// Some(List(canUpdateConnectorMethod))
-// )
-//
-// lazy val updateConnectorMethod: OBPEndpoint = {
-// case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// connectorMethodBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonConnectorMethodMethodBody]
-// }
-//
-// (cm, callContext) <- NewStyle.function.getJsonConnectorMethodById(
-// connectorMethodId,
-// cc.callContext
-// )
-//
-// connectorMethod = InternalConnector.createFunction(
-// cm.methodName,
-// connectorMethodBody.decodedMethodBody,
-// connectorMethodBody.programmingLang
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.head)
-// (connectorMethod, callContext) <- NewStyle.function
-// .updateJsonConnectorMethod(
-// connectorMethodId,
-// connectorMethodBody.methodBody,
-// connectorMethodBody.programmingLang,
-// callContext
-// )
-// } yield {
-// (connectorMethod, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConnectorMethod,
-// implementedInApiVersion,
-// nameOf(getConnectorMethod),
-// "GET",
-// "/management/connector-methods/CONNECTOR_METHOD_ID",
-// "Get Connector Method by Id",
-// s"""Get an internal connector by CONNECTOR_METHOD_ID.
-// |
-// |""",
-// EmptyBody,
-// jsonScalaConnectorMethod,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConnectorMethod),
-// Some(List(canGetConnectorMethod))
-// )
-//
-// lazy val getConnectorMethod: OBPEndpoint = {
-// case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (connectorMethod, callContext) <- NewStyle.function
-// .getJsonConnectorMethodById(connectorMethodId, cc.callContext)
-// } yield {
-// (connectorMethod, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllConnectorMethods,
-// implementedInApiVersion,
-// nameOf(getAllConnectorMethods),
-// "GET",
-// "/management/connector-methods",
-// "Get all Connector Methods",
-// s"""Get all Connector Methods.
-// |
-// |""",
-// EmptyBody,
-// ListResult("connectors_methods", jsonScalaConnectorMethod :: Nil),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConnectorMethod),
-// Some(List(canGetAllConnectorMethods))
-// )
-//
-// lazy val getAllConnectorMethods: OBPEndpoint = {
-// case "management" :: "connector-methods" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (connectorMethods, callContext) <- NewStyle.function
-// .getJsonConnectorMethods(cc.callContext)
-// } yield {
-// (
-// ListResult("connector_methods", connectorMethods),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(createDynamicResourceDoc),
-// "POST",
-// "/management/dynamic-resource-docs",
-// "Create Dynamic Resource Doc",
-// s"""Create a Dynamic Resource Doc.
-// |
-// |The connector_method_body is URL-encoded format String
-// |""",
-// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None),
-// jsonDynamicResourceDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canCreateDynamicResourceDoc))
-// )
-//
-// lazy val createDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// jsonDynamicResourceDoc <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicResourceDoc]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = cc.callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(
-// jsonDynamicResourceDoc.requestVerb
-// )
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""",
-// cc = cc.callContext
-// ) {
-// (
-// jsonDynamicResourceDoc.requestVerb,
-// jsonDynamicResourceDoc.exampleRequestBody
-// ) match {
-// case (
-// "GET" | "DELETE",
-// Some(JString(s))
-// ) => // we support the empty string "" here
-// StringUtils.isBlank(s)
-// case (
-// "GET" | "DELETE",
-// Some(requestBody)
-// ) => // we add the guard, we forbid any json objects in GET/DELETE request body.
-// requestBody == JNothing
-// case _ => true
-// }
-// }
-// _ =
-// try {
-// CompiledObjects(
-// jsonDynamicResourceDoc.exampleRequestBody,
-// jsonDynamicResourceDoc.successResponseBody,
-// jsonDynamicResourceDoc.methodBody
-// )
-// .validateDependency()
-// } catch {
-// case e: JsonResponseException =>
-// throw e
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isJsonDynamicResourceDocExists(
-// None,
-// jsonDynamicResourceDoc.requestVerb,
-// jsonDynamicResourceDoc.requestUrl,
-// Some(cc)
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique",
-// cc = callContext
-// ) {
-// (!isExists)
-// }
-//
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .createJsonDynamicResourceDoc(
-// None,
-// jsonDynamicResourceDoc,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(updateDynamicResourceDoc),
-// "PUT",
-// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Update Dynamic Resource Doc",
-// s"""Update a Dynamic Resource Doc.
-// |
-// |The connector_method_body is URL-encoded format String
-// |""",
-// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None),
-// jsonDynamicResourceDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canUpdateDynamicResourceDoc))
-// )
-//
-// lazy val updateDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicResourceDocBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicResourceDoc]
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = cc.callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(
-// dynamicResourceDocBody.requestVerb
-// )
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""",
-// cc = cc.callContext
-// ) {
-// (
-// dynamicResourceDocBody.requestVerb,
-// dynamicResourceDocBody.exampleRequestBody
-// ) match {
-// case ("GET" | "DELETE", Some(JString(s))) =>
-// StringUtils.isBlank(s)
-// case ("GET" | "DELETE", Some(requestBody)) =>
-// requestBody == JNothing
-// case _ => true
-// }
-// }
-//
-// _ =
-// try {
-// CompiledObjects(
-// jsonDynamicResourceDoc.exampleRequestBody,
-// jsonDynamicResourceDoc.successResponseBody,
-// jsonDynamicResourceDoc.methodBody
-// )
-// .validateDependency()
-// } catch {
-// case e: JsonResponseException =>
-// throw e
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-//
-// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(
-// None,
-// dynamicResourceDocId,
-// cc.callContext
-// )
-//
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .updateJsonDynamicResourceDoc(
-// None,
-// dynamicResourceDocBody.copy(dynamicResourceDocId =
-// Some(dynamicResourceDocId)
-// ),
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(deleteDynamicResourceDoc),
-// "DELETE",
-// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Delete Dynamic Resource Doc",
-// s"""Delete a Dynamic Resource Doc.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canDeleteDynamicResourceDoc))
-// )
-//
-// lazy val deleteDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(
-// None,
-// dynamicResourceDocId,
-// cc.callContext
-// )
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .deleteJsonDynamicResourceDocById(
-// None,
-// dynamicResourceDocId,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(getDynamicResourceDoc),
-// "GET",
-// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Get Dynamic Resource Doc by Id",
-// s"""Get a Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID.
-// |
-// |""",
-// EmptyBody,
-// jsonDynamicResourceDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canGetDynamicResourceDoc))
-// )
-//
-// lazy val getDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .getJsonDynamicResourceDocById(
-// None,
-// dynamicResourceDocId,
-// cc.callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllDynamicResourceDocs,
-// implementedInApiVersion,
-// nameOf(getAllDynamicResourceDocs),
-// "GET",
-// "/management/dynamic-resource-docs",
-// "Get all Dynamic Resource Docs",
-// s"""Get all Dynamic Resource Docs.
-// |
-// |""",
-// EmptyBody,
-// ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canGetAllDynamicResourceDocs))
-// )
-//
-// lazy val getAllDynamicResourceDocs: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicResourceDocs, callContext) <- NewStyle.function
-// .getJsonDynamicResourceDocs(None, cc.callContext)
-// } yield {
-// (
-// ListResult("dynamic-resource-docs", dynamicResourceDocs),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(createBankLevelDynamicResourceDoc),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-resource-docs",
-// "Create Bank Level Dynamic Resource Doc",
-// s"""Create a Bank Level Dynamic Resource Doc.
-// |
-// |The connector_method_body is URL-encoded format String
-// |""",
-// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None),
-// jsonDynamicResourceDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canCreateBankLevelDynamicResourceDoc))
-// )
-//
-// lazy val createBankLevelDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// jsonDynamicResourceDoc <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicResourceDoc]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = cc.callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(
-// jsonDynamicResourceDoc.requestVerb
-// )
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""",
-// cc = cc.callContext
-// ) {
-// (
-// jsonDynamicResourceDoc.requestVerb,
-// jsonDynamicResourceDoc.exampleRequestBody
-// ) match {
-// case (
-// "GET" | "DELETE",
-// Some(JString(s))
-// ) => // we support the empty string "" here
-// StringUtils.isBlank(s)
-// case (
-// "GET" | "DELETE",
-// Some(requestBody)
-// ) => // we add the guard, we forbid any json objects in GET/DELETE request body.
-// requestBody == JNothing
-// case _ => true
-// }
-// }
-// _ =
-// try {
-// CompiledObjects(
-// jsonDynamicResourceDoc.exampleRequestBody,
-// jsonDynamicResourceDoc.successResponseBody,
-// jsonDynamicResourceDoc.methodBody
-// )
-// .validateDependency()
-// } catch {
-// case e: JsonResponseException =>
-// throw e
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-// _ =
-// try {
-// CompiledObjects(
-// jsonDynamicResourceDoc.exampleRequestBody,
-// jsonDynamicResourceDoc.successResponseBody,
-// jsonDynamicResourceDoc.methodBody
-// )
-// } catch {
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-//
-// (isExists, callContext) <- NewStyle.function
-// .isJsonDynamicResourceDocExists(
-// Some(bankId),
-// jsonDynamicResourceDoc.requestVerb,
-// jsonDynamicResourceDoc.requestUrl,
-// Some(cc)
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique",
-// cc = callContext
-// ) {
-// (!isExists)
-// }
-//
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .createJsonDynamicResourceDoc(
-// Some(bankId),
-// jsonDynamicResourceDoc,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(updateBankLevelDynamicResourceDoc),
-// "PUT",
-// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Update Bank Level Dynamic Resource Doc",
-// s"""Update a Bank Level Dynamic Resource Doc.
-// |
-// |The connector_method_body is URL-encoded format String
-// |""",
-// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None),
-// jsonDynamicResourceDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canUpdateBankLevelDynamicResourceDoc))
-// )
-//
-// lazy val updateBankLevelDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicResourceDocBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicResourceDoc]
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = cc.callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(
-// dynamicResourceDocBody.requestVerb
-// )
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""",
-// cc = cc.callContext
-// ) {
-// (
-// dynamicResourceDocBody.requestVerb,
-// dynamicResourceDocBody.exampleRequestBody
-// ) match {
-// case ("GET" | "DELETE", Some(JString(s))) =>
-// StringUtils.isBlank(s)
-// case ("GET" | "DELETE", Some(requestBody)) =>
-// requestBody == JNothing
-// case _ => true
-// }
-// }
-// _ =
-// try {
-// CompiledObjects(
-// dynamicResourceDocBody.exampleRequestBody,
-// dynamicResourceDocBody.successResponseBody,
-// dynamicResourceDocBody.methodBody
-// )
-// .validateDependency()
-// } catch {
-// case e: JsonResponseException =>
-// throw e
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-//
-// _ =
-// try {
-// CompiledObjects(
-// dynamicResourceDocBody.exampleRequestBody,
-// dynamicResourceDocBody.successResponseBody,
-// jsonDynamicResourceDoc.methodBody
-// )
-// } catch {
-// case e: Exception =>
-// val jsonResponse = createErrorJsonResponse(
-// s"$DynamicCodeCompileFail ${e.getMessage}",
-// 400,
-// cc.correlationId
-// )
-// throw JsonResponseException(jsonResponse)
-// }
-//
-// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(
-// Some(bankId),
-// dynamicResourceDocId,
-// cc.callContext
-// )
-//
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .updateJsonDynamicResourceDoc(
-// Some(bankId),
-// dynamicResourceDocBody.copy(dynamicResourceDocId =
-// Some(dynamicResourceDocId)
-// ),
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelDynamicResourceDoc),
-// "DELETE",
-// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Delete Bank Level Dynamic Resource Doc",
-// s"""Delete a Bank Level Dynamic Resource Doc.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canDeleteBankLevelDynamicResourceDoc))
-// )
-//
-// lazy val deleteBankLevelDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(
-// Some(bankId),
-// dynamicResourceDocId,
-// cc.callContext
-// )
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .deleteJsonDynamicResourceDocById(
-// Some(bankId),
-// dynamicResourceDocId,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicResourceDoc),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID",
-// "Get Bank Level Dynamic Resource Doc by Id",
-// s"""Get a Bank Level Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID.
-// |
-// |""",
-// EmptyBody,
-// jsonDynamicResourceDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canGetBankLevelDynamicResourceDoc))
-// )
-//
-// lazy val getBankLevelDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .getJsonDynamicResourceDocById(
-// Some(bankId),
-// dynamicResourceDocId,
-// cc.callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllBankLevelDynamicResourceDocs,
-// implementedInApiVersion,
-// nameOf(getAllBankLevelDynamicResourceDocs),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-resource-docs",
-// "Get all Bank Level Dynamic Resource Docs",
-// s"""Get all Bank Level Dynamic Resource Docs.
-// |
-// |""",
-// EmptyBody,
-// ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canGetAllBankLevelDynamicResourceDocs))
-// )
-//
-// lazy val getAllBankLevelDynamicResourceDocs: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicResourceDocs, callContext) <- NewStyle.function
-// .getJsonDynamicResourceDocs(Some(bankId), cc.callContext)
-// } yield {
-// (
-// ListResult("dynamic-resource-docs", dynamicResourceDocs),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// buildDynamicEndpointTemplate,
-// implementedInApiVersion,
-// nameOf(buildDynamicEndpointTemplate),
-// "POST",
-// "/management/dynamic-resource-docs/endpoint-code",
-// "Create Dynamic Resource Doc endpoint code",
-// s"""Create a Dynamic Resource Doc endpoint code.
-// |
-// |copy the response and past to ${nameOf(
-// PractiseEndpoint
-// )}, So you can have the benefits of
-// |auto compilation and debug
-// |""",
-// jsonResourceDocFragment,
-// jsonCodeTemplateJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// None
-// )
-//
-// lazy val buildDynamicEndpointTemplate: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: "endpoint-code" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// resourceDocFragment <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $ResourceDocFragment",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[ResourceDocFragment]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = cc.callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(
-// resourceDocFragment.requestVerb
-// )
-// }
-//
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""",
-// cc = cc.callContext
-// ) {
-// (
-// resourceDocFragment.requestVerb,
-// resourceDocFragment.exampleRequestBody
-// ) match {
-// case ("GET" | "DELETE", Some(JString(s))) =>
-// StringUtils.isBlank(s)
-// case ("GET" | "DELETE", Some(requestBody)) =>
-// requestBody == JNothing
-// case _ => true
-// }
-// }
-//
-// code = DynamicEndpointCodeGenerator.buildTemplate(
-// resourceDocFragment
-// )
-//
-// } yield {
-// (
-// JsonCodeTemplateJson(URLEncoder.encode(code, "UTF-8")),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(createDynamicMessageDoc),
-// "POST",
-// "/management/dynamic-message-docs",
-// "Create Dynamic Message Doc",
-// s"""Create a Dynamic Message Doc.
-// |""",
-// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None),
-// jsonDynamicMessageDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canCreateDynamicMessageDoc))
-// )
-//
-// lazy val createDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "dynamic-message-docs" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicMessageDoc <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicMessageDoc]
-// }
-// (dynamicMessageDocExisted, callContext) <- NewStyle.function
-// .isJsonDynamicMessageDocExists(
-// None,
-// dynamicMessageDoc.process,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists",
-// cc = callContext
-// ) {
-// (!dynamicMessageDocExisted)
-// }
-// connectorMethod = DynamicConnector.createFunction(
-// dynamicMessageDoc.programmingLang,
-// dynamicMessageDoc.decodedMethodBody
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.orNull)
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .createJsonDynamicMessageDoc(None, dynamicMessageDoc, callContext)
-// } yield {
-// (dynamicMessageDoc, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(createBankLevelDynamicMessageDoc),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-message-docs",
-// "Create Bank Level Dynamic Message Doc",
-// s"""Create a Bank Level Dynamic Message Doc.
-// |""",
-// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None),
-// jsonDynamicMessageDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canCreateBankLevelDynamicMessageDoc))
-// )
-//
-// lazy val createBankLevelDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicMessageDoc <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicMessageDoc]
-// }
-// (dynamicMessageDocExisted, callContext) <- NewStyle.function
-// .isJsonDynamicMessageDocExists(
-// Some(bankId),
-// dynamicMessageDoc.process,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists",
-// cc = callContext
-// ) {
-// (!dynamicMessageDocExisted)
-// }
-// connectorMethod = DynamicConnector.createFunction(
-// dynamicMessageDoc.programmingLang,
-// dynamicMessageDoc.decodedMethodBody
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.orNull)
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .createJsonDynamicMessageDoc(
-// Some(bankId),
-// dynamicMessageDoc,
-// callContext
-// )
-// } yield {
-// (dynamicMessageDoc, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(updateDynamicMessageDoc),
-// "PUT",
-// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Update Dynamic Message Doc",
-// s"""Update a Dynamic Message Doc.
-// |""",
-// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None),
-// jsonDynamicMessageDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canUpdateDynamicMessageDoc))
-// )
-//
-// lazy val updateDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicMessageDocBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicMessageDoc]
-// }
-// connectorMethod = DynamicConnector.createFunction(
-// dynamicMessageDocBody.programmingLang,
-// dynamicMessageDocBody.decodedMethodBody
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(
-// failMsg = errorMsg,
-// cc = cc.callContext
-// ) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.orNull)
-// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(
-// None,
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .updateJsonDynamicMessageDoc(
-// None,
-// dynamicMessageDocBody.copy(dynamicMessageDocId =
-// Some(dynamicMessageDocId)
-// ),
-// callContext
-// )
-// } yield {
-// (dynamicMessageDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(getDynamicMessageDoc),
-// "GET",
-// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Get Dynamic Message Doc",
-// s"""Get a Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID.
-// |
-// |""",
-// EmptyBody,
-// jsonDynamicMessageDoc,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canGetDynamicMessageDoc))
-// )
-//
-// lazy val getDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .getJsonDynamicMessageDocById(
-// None,
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// } yield {
-// (dynamicMessageDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllDynamicMessageDocs,
-// implementedInApiVersion,
-// nameOf(getAllDynamicMessageDocs),
-// "GET",
-// "/management/dynamic-message-docs",
-// "Get all Dynamic Message Docs",
-// s"""Get all Dynamic Message Docs.
-// |
-// |""",
-// EmptyBody,
-// ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canGetAllDynamicMessageDocs))
-// )
-//
-// lazy val getAllDynamicMessageDocs: OBPEndpoint = {
-// case "management" :: "dynamic-message-docs" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicMessageDocs, callContext) <- NewStyle.function
-// .getJsonDynamicMessageDocs(None, cc.callContext)
-// } yield {
-// (
-// ListResult("dynamic-message-docs", dynamicMessageDocs),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(deleteDynamicMessageDoc),
-// "DELETE",
-// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Delete Dynamic Message Doc",
-// s"""Delete a Dynamic Message Doc.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canDeleteDynamicMessageDoc))
-// )
-//
-// lazy val deleteDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(
-// None,
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .deleteJsonDynamicMessageDocById(
-// None,
-// dynamicMessageDocId,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(updateBankLevelDynamicMessageDoc),
-// "PUT",
-// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Update Bank Level Dynamic Message Doc",
-// s"""Update a Bank Level Dynamic Message Doc.
-// |""",
-// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None),
-// jsonDynamicMessageDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canUpdateDynamicMessageDoc))
-// )
-//
-// lazy val updateBankLevelDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicMessageDocBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[JsonDynamicMessageDoc]
-// }
-// connectorMethod = DynamicConnector.createFunction(
-// dynamicMessageDocBody.programmingLang,
-// dynamicMessageDocBody.decodedMethodBody
-// )
-// errorMsg =
-// if (connectorMethod.isEmpty)
-// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}"
-// else ""
-// _ <- Helper.booleanToFuture(
-// failMsg = errorMsg,
-// cc = cc.callContext
-// ) {
-// connectorMethod.isDefined
-// }
-// _ = Validation.validateDependency(connectorMethod.orNull)
-// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(
-// Some(bankId),
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .updateJsonDynamicMessageDoc(
-// Some(bankId),
-// dynamicMessageDocBody.copy(dynamicMessageDocId =
-// Some(dynamicMessageDocId)
-// ),
-// callContext
-// )
-// } yield {
-// (dynamicMessageDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicMessageDoc),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Get Bank Level Dynamic Message Doc",
-// s"""Get a Bank Level Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID.
-// |
-// |""",
-// EmptyBody,
-// jsonDynamicMessageDoc,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canGetBankLevelDynamicMessageDoc))
-// )
-//
-// lazy val getBankLevelDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicMessageDoc, callContext) <- NewStyle.function
-// .getJsonDynamicMessageDocById(
-// None,
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// } yield {
-// (dynamicMessageDoc, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllBankLevelDynamicMessageDocs,
-// implementedInApiVersion,
-// nameOf(getAllBankLevelDynamicMessageDocs),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-message-docs",
-// "Get all Bank Level Dynamic Message Docs",
-// s"""Get all Bank Level Dynamic Message Docs.
-// |
-// |""",
-// EmptyBody,
-// ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canGetAllDynamicMessageDocs))
-// )
-//
-// lazy val getAllBankLevelDynamicMessageDocs: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (dynamicMessageDocs, callContext) <- NewStyle.function
-// .getJsonDynamicMessageDocs(Some(bankId), cc.callContext)
-// } yield {
-// (
-// ListResult("dynamic-message-docs", dynamicMessageDocs),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelDynamicMessageDoc,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelDynamicMessageDoc),
-// "DELETE",
-// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID",
-// "Delete Bank Level Dynamic Message Doc",
-// s"""Delete a Bank Level Dynamic Message Doc.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicMessageDoc),
-// Some(List(canDeleteBankLevelDynamicMessageDoc))
-// )
-//
-// lazy val deleteBankLevelDynamicMessageDoc: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(
-// Some(bankId),
-// dynamicMessageDocId,
-// cc.callContext
-// )
-// (dynamicResourceDoc, callContext) <- NewStyle.function
-// .deleteJsonDynamicMessageDocById(
-// Some(bankId),
-// dynamicMessageDocId,
-// callContext
-// )
-// } yield {
-// (dynamicResourceDoc, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createEndpointMapping,
-// implementedInApiVersion,
-// nameOf(createEndpointMapping),
-// "POST",
-// "/management/endpoint-mappings",
-// "Create Endpoint Mapping",
-// s"""Create an Endpoint Mapping.
-// |
-// |Note: at moment only support the dynamic endpoints
-// |""",
-// endpointMappingRequestBodyExample,
-// endpointMappingResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canCreateEndpointMapping))
-// )
-//
-// lazy val createEndpointMapping: OBPEndpoint = {
-// case "management" :: "endpoint-mappings" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// createEndpointMappingMethod(None, json, cc)
-// }
-// }
-//
-// private def createEndpointMappingMethod(
-// bankId: Option[String],
-// json: JValue,
-// cc: CallContext
-// ) = {
-// for {
-// endpointMapping <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointMappingCommons].copy(bankId = bankId)
-// }
-// (endpointMapping, callContext) <- NewStyle.function
-// .createOrUpdateEndpointMapping(
-// bankId,
-// endpointMapping.copy(
-// endpointMappingId = None,
-// bankId = bankId
-// ), // create need to make sure, endpointMappingId is None, and bankId must be from URL.
-// cc.callContext
-// )
-// } yield {
-// val commonsData: EndpointMappingCommons = endpointMapping
-// (commonsData.toJson, HttpCode.`201`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateEndpointMapping,
-// implementedInApiVersion,
-// nameOf(updateEndpointMapping),
-// "PUT",
-// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Update Endpoint Mapping",
-// s"""Update an Endpoint Mapping.
-// |""",
-// endpointMappingRequestBodyExample,
-// endpointMappingResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canUpdateEndpointMapping))
-// )
-//
-// lazy val updateEndpointMapping: OBPEndpoint = {
-// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateEndpointMappingMethod(None, endpointMappingId, json, cc)
-// }
-// }
-//
-// private def updateEndpointMappingMethod(
-// bankId: Option[String],
-// endpointMappingId: String,
-// json: JValue,
-// cc: CallContext
-// ) = {
-// for {
-// endpointMappingBody <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointMappingCommons].copy(bankId = bankId)
-// }
-// (endpointMapping, callContext) <- NewStyle.function
-// .getEndpointMappingById(bankId, endpointMappingId, cc.callContext)
-// _ <- Helper.booleanToFuture(
-// s"$InvalidJsonFormat operation_id has to be the same in the URL (${endpointMapping.operationId}) and Body (${endpointMappingBody.operationId}). ",
-// 400,
-// cc.callContext
-// ) {
-// endpointMapping.operationId == endpointMappingBody.operationId
-// }
-// (endpointMapping, callContext) <- NewStyle.function
-// .createOrUpdateEndpointMapping(
-// bankId,
-// endpointMappingBody.copy(
-// endpointMappingId = Some(endpointMappingId),
-// bankId = bankId
-// ), // Update must set the endpointId and BankId must be from URL
-// callContext
-// )
-// } yield {
-// val commonsData: EndpointMappingCommons = endpointMapping
-// (commonsData.toJson, HttpCode.`201`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getEndpointMapping,
-// implementedInApiVersion,
-// nameOf(getEndpointMapping),
-// "GET",
-// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Get Endpoint Mapping by Id",
-// s"""Get an Endpoint Mapping by ENDPOINT_MAPPING_ID.
-// |
-// |""",
-// EmptyBody,
-// endpointMappingResponseBodyExample,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canGetEndpointMapping))
-// )
-//
-// lazy val getEndpointMapping: OBPEndpoint = {
-// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getEndpointMappingMethod(None, endpointMappingId, cc)
-// }
-// }
-//
-// private def getEndpointMappingMethod(
-// bankId: Option[String],
-// endpointMappingId: String,
-// cc: CallContext
-// ) = {
-// for {
-// (endpointMapping, callContext) <- NewStyle.function
-// .getEndpointMappingById(bankId, endpointMappingId, cc.callContext)
-// } yield {
-// val commonsData: EndpointMappingCommons = endpointMapping
-// (commonsData.toJson, HttpCode.`201`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllEndpointMappings,
-// implementedInApiVersion,
-// nameOf(getAllEndpointMappings),
-// "GET",
-// "/management/endpoint-mappings",
-// "Get all Endpoint Mappings",
-// s"""Get all Endpoint Mappings.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "endpoint-mappings",
-// endpointMappingResponseBodyExample :: Nil
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canGetAllEndpointMappings))
-// )
-//
-// lazy val getAllEndpointMappings: OBPEndpoint = {
-// case "management" :: "endpoint-mappings" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getEndpointMappingsMethod(None, cc)
-// }
-// }
-//
-// private def getEndpointMappingsMethod(
-// bankId: Option[String],
-// cc: CallContext
-// ) = {
-// for {
-// (endpointMappings, callContext) <- NewStyle.function
-// .getEndpointMappings(bankId, cc.callContext)
-// } yield {
-// val listCommons: List[EndpointMappingCommons] = endpointMappings
-// (
-// ListResult("endpoint-mappings", listCommons.map(_.toJson)),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteEndpointMapping,
-// implementedInApiVersion,
-// nameOf(deleteEndpointMapping),
-// "DELETE",
-// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Delete Endpoint Mapping",
-// s"""Delete a Endpoint Mapping.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canDeleteEndpointMapping))
-// )
-//
-// lazy val deleteEndpointMapping: OBPEndpoint = {
-// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteEndpointMappingMethod(None, endpointMappingId, cc)
-// }
-// }
-//
-// private def deleteEndpointMappingMethod(
-// bankId: Option[String],
-// endpointMappingId: String,
-// cc: CallContext
-// ) = {
-// for {
-// (deleted, callContext) <- NewStyle.function.deleteEndpointMapping(
-// bankId,
-// endpointMappingId,
-// cc.callContext
-// )
-// } yield {
-// (deleted, HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelEndpointMapping,
-// implementedInApiVersion,
-// nameOf(createBankLevelEndpointMapping),
-// "POST",
-// "/management/banks/BANK_ID/endpoint-mappings",
-// "Create Bank Level Endpoint Mapping",
-// s"""Create an Bank Level Endpoint Mapping.
-// |
-// |Note: at moment only support the dynamic endpoints
-// |""",
-// endpointMappingRequestBodyExample,
-// endpointMappingResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canCreateBankLevelEndpointMapping, canCreateEndpointMapping))
-// )
-//
-// lazy val createBankLevelEndpointMapping: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// createEndpointMappingMethod(Some(bankId), json, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelEndpointMapping,
-// implementedInApiVersion,
-// nameOf(updateBankLevelEndpointMapping),
-// "PUT",
-// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Update Bank Level Endpoint Mapping",
-// s"""Update an Bank Level Endpoint Mapping.
-// |""",
-// endpointMappingRequestBodyExample,
-// endpointMappingResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canUpdateBankLevelEndpointMapping, canUpdateEndpointMapping))
-// )
-//
-// lazy val updateBankLevelEndpointMapping: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// updateEndpointMappingMethod(Some(bankId), endpointMappingId, json, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelEndpointMapping,
-// implementedInApiVersion,
-// nameOf(getBankLevelEndpointMapping),
-// "GET",
-// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Get Bank Level Endpoint Mapping",
-// s"""Get an Bank Level Endpoint Mapping by ENDPOINT_MAPPING_ID.
-// |
-// |""",
-// EmptyBody,
-// endpointMappingResponseBodyExample,
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canGetBankLevelEndpointMapping, canGetEndpointMapping))
-// )
-//
-// lazy val getBankLevelEndpointMapping: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getEndpointMappingMethod(Some(bankId), endpointMappingId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllBankLevelEndpointMappings,
-// implementedInApiVersion,
-// nameOf(getAllBankLevelEndpointMappings),
-// "GET",
-// "/management/banks/BANK_ID/endpoint-mappings",
-// "Get all Bank Level Endpoint Mappings",
-// s"""Get all Bank Level Endpoint Mappings.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "endpoint-mappings",
-// endpointMappingResponseBodyExample :: Nil
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canGetAllBankLevelEndpointMappings, canGetAllEndpointMappings))
-// )
-//
-// lazy val getAllBankLevelEndpointMappings: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// getEndpointMappingsMethod(Some(bankId), cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelEndpointMapping,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelEndpointMapping),
-// "DELETE",
-// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID",
-// "Delete Bank Level Endpoint Mapping",
-// s"""Delete a Bank Level Endpoint Mapping.
-// |""",
-// EmptyBody,
-// BooleanBody(true),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagEndpointMapping),
-// Some(List(canDeleteBankLevelEndpointMapping, canDeleteEndpointMapping))
-// )
-//
-// lazy val deleteBankLevelEndpointMapping: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteEndpointMappingMethod(Some(bankId), endpointMappingId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmSupportedCurrencies,
-// implementedInApiVersion,
-// nameOf(updateAtmSupportedCurrencies),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/supported-currencies",
-// "Update ATM Supported Currencies",
-// s"""Update ATM Supported Currencies.
-// |""",
-// supportedCurrenciesJson,
-// atmSupportedCurrenciesJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmSupportedCurrencies: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "supported-currencies" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// supportedCurrencies <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedCurrenciesJson]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[SupportedCurrenciesJson].supported_currencies
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function.updateAtmSupportedCurrencies(
-// bankId,
-// atmId,
-// supportedCurrencies,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmSupportedCurrenciesJson(
-// atm.atmId.value,
-// atm.supportedCurrencies.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmSupportedLanguages,
-// implementedInApiVersion,
-// nameOf(updateAtmSupportedLanguages),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/supported-languages",
-// "Update ATM Supported Languages",
-// s"""Update ATM Supported Languages.
-// |""",
-// supportedLanguagesJson,
-// atmSupportedLanguagesJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmSupportedLanguages: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "supported-languages" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// supportedLanguages <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedLanguagesJson]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[SupportedLanguagesJson].supported_languages
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function.updateAtmSupportedLanguages(
-// bankId,
-// atmId,
-// supportedLanguages,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmSupportedLanguagesJson(
-// atm.atmId.value,
-// atm.supportedLanguages.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmAccessibilityFeatures,
-// implementedInApiVersion,
-// nameOf(updateAtmAccessibilityFeatures),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/accessibility-features",
-// "Update ATM Accessibility Features",
-// s"""Update ATM Accessibility Features.
-// |""",
-// accessibilityFeaturesJson,
-// atmAccessibilityFeaturesJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmAccessibilityFeatures: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "accessibility-features" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// accessibilityFeatures <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AccessibilityFeaturesJson]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AccessibilityFeaturesJson].accessibility_features
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function
-// .updateAtmAccessibilityFeatures(
-// bankId,
-// atmId,
-// accessibilityFeatures,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmAccessibilityFeaturesJson(
-// atm.atmId.value,
-// atm.accessibilityFeatures.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmServices,
-// implementedInApiVersion,
-// nameOf(updateAtmServices),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/services",
-// "Update ATM Services",
-// s"""Update ATM Services.
-// |""",
-// atmServicesJson,
-// atmServicesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmServices: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "services" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// services <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmServicesJsonV400]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AtmServicesJsonV400].services
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function.updateAtmServices(
-// bankId,
-// atmId,
-// services,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmServicesResponseJsonV400(
-// atm.atmId.value,
-// atm.services.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmNotes,
-// implementedInApiVersion,
-// nameOf(updateAtmNotes),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/notes",
-// "Update ATM Notes",
-// s"""Update ATM Notes.
-// |""",
-// atmNotesJson,
-// atmNotesResponseJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmNotes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "notes" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// notes <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmNotesJsonV400]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AtmNotesJsonV400].notes
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function.updateAtmNotes(
-// bankId,
-// atmId,
-// notes,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmServicesResponseJsonV400(
-// atm.atmId.value,
-// atm.notes.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmLocationCategories,
-// implementedInApiVersion,
-// nameOf(updateAtmLocationCategories),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/location-categories",
-// "Update ATM Location Categories",
-// s"""Update ATM Location Categories.
-// |""",
-// atmLocationCategoriesJsonV400,
-// atmLocationCategoriesResponseJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-//
-// lazy val updateAtmLocationCategories: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: "location-categories" :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// locationCategories <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmLocationCategoriesJsonV400]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AtmLocationCategoriesJsonV400].location_categories
-// }
-// (_, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (atm, callContext) <- NewStyle.function.updateAtmLocationCategories(
-// bankId,
-// atmId,
-// locationCategories,
-// cc.callContext
-// )
-// } yield {
-// (
-// AtmLocationCategoriesResponseJsonV400(
-// atm.atmId.value,
-// atm.locationCategories.getOrElse(Nil)
-// ),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createAtm,
-// implementedInApiVersion,
-// nameOf(createAtm),
-// "POST",
-// "/banks/BANK_ID/atms",
-// "Create ATM",
-// s"""Create ATM.""",
-// atmJsonV400,
-// atmJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canCreateAtm, canCreateAtmAtAnyBank))
-// )
-// lazy val createAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// atmJsonV400 <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}",
-// 400,
-// cc.callContext
-// ) {
-// val atm = json.extract[AtmJsonV400]
-// // Make sure the Create contains proper ATM ID
-// atm.id.get
-// atm
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body",
-// 400,
-// cc.callContext
-// ) { atmJsonV400.bank_id == bankId.value }
-// atm <- NewStyle.function.tryons(
-// ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm",
-// 400,
-// cc.callContext
-// ) {
-// JSONFactory400.transformToAtmFromV400(atmJsonV400)
-// }
-// (atm, callContext) <- NewStyle.function.createOrUpdateAtm(
-// atm,
-// cc.callContext
-// )
-// } yield {
-// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtm,
-// implementedInApiVersion,
-// nameOf(updateAtm),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "UPDATE ATM",
-// s"""Update ATM.""",
-// atmJsonV400.copy(id = None),
-// atmJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canUpdateAtm, canUpdateAtmAtAnyBank))
-// )
-// lazy val updateAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (atm, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// atmJsonV400 <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[AtmJsonV400]
-// }
-// _ <- Helper.booleanToFuture(
-// s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body",
-// 400,
-// cc.callContext
-// ) { atmJsonV400.bank_id == bankId.value }
-// atm <- NewStyle.function.tryons(
-// ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm",
-// 400,
-// cc.callContext
-// ) {
-// JSONFactory400.transformToAtmFromV400(
-// atmJsonV400.copy(id = Some(atmId.value))
-// )
-// }
-// (atm, callContext) <- NewStyle.function.createOrUpdateAtm(
-// atm,
-// cc.callContext
-// )
-// } yield {
-// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAtm,
-// implementedInApiVersion,
-// nameOf(deleteAtm),
-// "DELETE",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "Delete ATM",
-// s"""Delete ATM.""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canDeleteAtmAtAnyBank, canDeleteAtm))
-// )
-// lazy val deleteAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: Nil JsonDelete _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (atm, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// cc.callContext
-// )
-// (deleted, callContext) <- NewStyle.function.deleteAtm(
-// atm,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAtms,
-// implementedInApiVersion,
-// nameOf(getAtms),
-// "GET",
-// "/banks/BANK_ID/atms",
-// "Get Bank ATMS",
-// s"""Returns information about ATMs for a single bank specified by BANK_ID including:
-// |
-// |* Address
-// |* Geo Location
-// |* License the data under this endpoint is released under
-// |
-// |Pagination:
-// |
-// |By default, 100 records are returned.
-// |
-// |You can use the url query parameters *limit* and *offset* for pagination
-// |
-// |${userAuthenticationMessage(!getAtmsIsPublic)}""".stripMargin,
-// EmptyBody,
-// atmsJsonV400,
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-// lazy val getAtms: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val limit = ObpS.param("limit")
-// val offset = ObpS.param("offset")
-// for {
-// (_, callContext) <- getAtmsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = s"${InvalidNumber} limit:${limit.getOrElse("")}",
-// cc = callContext
-// ) {
-// limit match {
-// case Full(i) => i.toList.forall(c => Character.isDigit(c) == true)
-// case _ => true
-// }
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = maximumLimitExceeded,
-// cc = callContext
-// ) {
-// limit match {
-// case Full(i) if i.toInt > 10000 => false
-// case _ => true
-// }
-// }
-// (atms, callContext) <- NewStyle.function.getAtmsByBankId(
-// bankId,
-// offset,
-// limit,
-// cc.callContext
-// )
-// } yield {
-// (JSONFactory400.createAtmsJsonV400(atms), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAtm,
-// implementedInApiVersion,
-// nameOf(getAtm),
-// "GET",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "Get Bank ATM",
-// s"""Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:
-// |
-// |* Address
-// |* Geo Location
-// |* License the data under this endpoint is released under
-// |${userAuthenticationMessage(!getAtmsIsPublic)}
-// |""".stripMargin,
-// EmptyBody,
-// atmJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-// lazy val getAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(
-// atmId
-// ) :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getAtmsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (atm, callContext) <- NewStyle.function.getAtm(
-// bankId,
-// atmId,
-// callContext
-// )
-// } yield {
-// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createSystemLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(createSystemLevelEndpointTag),
-// "POST",
-// "/management/endpoints/OPERATION_ID/tags",
-// "Create System Level Endpoint Tag",
-// s"""Create System Level Endpoint Tag
-// |
-// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds
-// |
-// |""".stripMargin,
-// endpointTagJson400,
-// bankLevelEndpointTagResponseJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canCreateSystemLevelEndpointTag))
-// )
-// lazy val createSystemLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// endpointTag <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointTagJson400]
-// }
-// (endpointTagExisted, callContext) <- NewStyle.function
-// .checkSystemLevelEndpointTagExists(
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})",
-// cc = callContext
-// ) {
-// (!endpointTagExisted)
-// }
-// (endpointTag, callContext) <- NewStyle.function
-// .createSystemLevelEndpointTag(
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// } yield {
-// (
-// SystemLevelEndpointTagResponseJson400(
-// endpointTag.endpointTagId.getOrElse(""),
-// endpointTag.operationId,
-// endpointTag.tagName
-// ),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateSystemLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(updateSystemLevelEndpointTag),
-// "PUT",
-// "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID",
-// "Update System Level Endpoint Tag",
-// s"""Update System Level Endpoint Tag, you can only update the tag_name here, operation_id can not be updated.
-// |
-// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds
-// |
-// |""".stripMargin,
-// endpointTagJson400,
-// bankLevelEndpointTagResponseJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// EndpointTagNotFoundByEndpointTagId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canUpdateSystemLevelEndpointTag))
-// )
-// lazy val updateSystemLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// endpointTag <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointTagJson400]
-// }
-// (_, callContext) <- NewStyle.function.getEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-// (endpointTagExisted, callContext) <- NewStyle.function
-// .checkSystemLevelEndpointTagExists(
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name",
-// cc = callContext
-// ) {
-// (!endpointTagExisted)
-// }
-// (endpointTagT, callContext) <- NewStyle.function
-// .updateSystemLevelEndpointTag(
-// endpointTagId,
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// } yield {
-// (
-// SystemLevelEndpointTagResponseJson400(
-// endpointTagT.endpointTagId.getOrElse(""),
-// endpointTagT.operationId,
-// endpointTagT.tagName
-// ),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemLevelEndpointTags,
-// implementedInApiVersion,
-// nameOf(getSystemLevelEndpointTags),
-// "GET",
-// "/management/endpoints/OPERATION_ID/tags",
-// "Get System Level Endpoint Tags",
-// s"""Get System Level Endpoint Tags.""",
-// EmptyBody,
-// bankLevelEndpointTagResponseJson400 :: Nil,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canGetSystemLevelEndpointTag))
-// )
-// lazy val getSystemLevelEndpointTags: OBPEndpoint = {
-// case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (endpointTags, callContext) <- NewStyle.function
-// .getSystemLevelEndpointTags(operationId, cc.callContext)
-// } yield {
-// (
-// endpointTags.map(endpointTagT =>
-// SystemLevelEndpointTagResponseJson400(
-// endpointTagT.endpointTagId.getOrElse(""),
-// endpointTagT.operationId,
-// endpointTagT.tagName
-// )
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSystemLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(deleteSystemLevelEndpointTag),
-// "DELETE",
-// "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID",
-// "Delete System Level Endpoint Tag",
-// s"""Delete System Level Endpoint Tag.""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canDeleteSystemLevelEndpointTag))
-// )
-// lazy val deleteSystemLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-//
-// (deleted, callContext) <- NewStyle.function.deleteEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(createBankLevelEndpointTag),
-// "POST",
-// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags",
-// "Create Bank Level Endpoint Tag",
-// s"""Create Bank Level Endpoint Tag
-// |
-// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds
-// |
-// |
-// |""".stripMargin,
-// endpointTagJson400,
-// bankLevelEndpointTagResponseJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canCreateBankLevelEndpointTag))
-// )
-// lazy val createBankLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// endpointTag <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointTagJson400]
-// }
-// (endpointTagExisted, callContext) <- NewStyle.function
-// .checkBankLevelEndpointTagExists(
-// bankId,
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})",
-// cc = callContext
-// ) {
-// (!endpointTagExisted)
-// }
-// (endpointTagT, callContext) <- NewStyle.function
-// .createBankLevelEndpointTag(
-// bankId,
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// } yield {
-// (
-// BankLevelEndpointTagResponseJson400(
-// endpointTagT.bankId.getOrElse(""),
-// endpointTagT.endpointTagId.getOrElse(""),
-// endpointTagT.operationId,
-// endpointTagT.tagName
-// ),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(updateBankLevelEndpointTag),
-// "PUT",
-// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID",
-// "Update Bank Level Endpoint Tag",
-// s"""Update Endpoint Tag, you can only update the tag_name here, operation_id can not be updated.
-// |
-// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds
-// |
-// |""".stripMargin,
-// endpointTagJson400,
-// bankLevelEndpointTagResponseJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// EndpointTagNotFoundByEndpointTagId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canUpdateBankLevelEndpointTag))
-// )
-// lazy val updateBankLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// endpointTag <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400",
-// 400,
-// cc.callContext
-// ) {
-// json.extract[EndpointTagJson400]
-// }
-// (_, callContext) <- NewStyle.function.getEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-// (endpointTagExisted, callContext) <- NewStyle.function
-// .checkBankLevelEndpointTagExists(
-// bankId,
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$EndpointTagAlreadyExists BANK_ID($bankId), OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name",
-// cc = callContext
-// ) {
-// (!endpointTagExisted)
-// }
-// (endpointTagT, callContext) <- NewStyle.function
-// .updateBankLevelEndpointTag(
-// bankId,
-// endpointTagId,
-// operationId,
-// endpointTag.tag_name,
-// cc.callContext
-// )
-// } yield {
-// (
-// BankLevelEndpointTagResponseJson400(
-// endpointTagT.bankId.getOrElse(""),
-// endpointTagT.endpointTagId.getOrElse(""),
-// endpointTagT.operationId,
-// endpointTagT.tagName
-// ),
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelEndpointTags,
-// implementedInApiVersion,
-// nameOf(getBankLevelEndpointTags),
-// "GET",
-// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags",
-// "Get Bank Level Endpoint Tags",
-// s"""Get Bank Level Endpoint Tags.""",
-// EmptyBody,
-// bankLevelEndpointTagResponseJson400 :: Nil,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canGetBankLevelEndpointTag))
-// )
-// lazy val getBankLevelEndpointTags: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (endpointTags, callContext) <- NewStyle.function
-// .getBankLevelEndpointTags(bankId, operationId, cc.callContext)
-// } yield {
-// (
-// endpointTags.map(endpointTagT =>
-// BankLevelEndpointTagResponseJson400(
-// endpointTagT.bankId.getOrElse(""),
-// endpointTagT.endpointTagId.getOrElse(""),
-// endpointTagT.operationId,
-// endpointTagT.tagName
-// )
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankLevelEndpointTag,
-// implementedInApiVersion,
-// nameOf(deleteBankLevelEndpointTag),
-// "DELETE",
-// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID",
-// "Delete Bank Level Endpoint Tag",
-// s"""Delete Bank Level Endpoint Tag.""",
-// EmptyBody,
-// Full(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canDeleteBankLevelEndpointTag))
-// )
-// lazy val deleteBankLevelEndpointTag: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-//
-// (deleted, callContext) <- NewStyle.function.deleteEndpointTag(
-// endpointTagId,
-// cc.callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMySpaces,
-// implementedInApiVersion,
-// nameOf(getMySpaces),
-// "GET",
-// "/my/spaces",
-// "Get My Spaces",
-// s"""Get My Spaces.""",
-// EmptyBody,
-// mySpaces,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagUser)
-// )
-// lazy val getMySpaces: OBPEndpoint = {
-// case "my" :: "spaces" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// entitlements <- NewStyle.function.getEntitlementsByUserId(
-// u.userId,
-// callContext
-// )
-// } yield {
-// (
-// MySpaces(
-// entitlements
-// .filter(
-// _.roleName == canReadDynamicResourceDocsAtOneBank.toString()
-// )
-// .map(entitlement => entitlement.bankId)
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProducts,
-// implementedInApiVersion,
-// "getProducts",
-// "GET",
-// "/banks/BANK_ID/products",
-// "Get Products",
-// s"""Returns information about the financial products offered by a bank specified by BANK_ID including:
-// |
-// |* Name
-// |* Code
-// |* Parent Product Code
-// |* More info URL
-// |* Terms And Conditions URL
-// |* Description
-// |* Terms and Conditions
-// |* License the data under this endpoint is released under
-// |
-// |The combination of bank_id and product_code is unique.
-// |
-// |Can filter with attributes name and values.
-// |URL params example: /banks/some-bank-id/products?&limit=50&offset=1
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productsJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-// lazy val getProducts: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2))
-// (products, callContext) <- NewStyle.function.getProducts(
-// bankId,
-// params,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createProductsJson(products),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createProduct,
-// implementedInApiVersion,
-// nameOf(createProduct),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE",
-// "Create Product",
-// s"""Create or Update Product for the Bank.
-// |
-// |
-// |Typical Super Family values / Asset classes are:
-// |
-// |Debt
-// |Equity
-// |FX
-// |Commodity
-// |Derivative
-// |
-// |$productHiearchyAndCollectionNote
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |
-// |""",
-// putProductJsonV400,
-// productJsonV400.copy(attributes = None, fees = None),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canCreateProduct, canCreateProductAtAnyBank))
-// )
-// lazy val createProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(
-// productCode
-// ) :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg =
-// createProductEntitlementsRequiredText
-// )(bankId.value, u.userId, createProductEntitlements, callContext)
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $PutProductJsonV400 "
-// product <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutProductJsonV400]
-// }
-// (parentProduct, callContext) <-
-// product.parent_product_code.trim.nonEmpty match {
-// case false =>
-// Future((Empty, callContext))
-// case true =>
-// NewStyle.function
-// .getProduct(
-// bankId,
-// ProductCode(product.parent_product_code),
-// callContext
-// )
-// .map(product => (Full(product._1), product._2))
-// }
-// (success, callContext) <- NewStyle.function.createOrUpdateProduct(
-// bankId = bankId.value,
-// code = productCode.value,
-// parentProductCode = parentProduct.map(_.code.value).toOption,
-// name = product.name,
-// category = null,
-// family = null,
-// superFamily = null,
-// moreInfoUrl = product.more_info_url,
-// termsAndConditionsUrl = product.terms_and_conditions_url,
-// details = null,
-// description = product.description,
-// metaLicenceId = product.meta.license.id,
-// metaLicenceName = product.meta.license.name,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createProductJson(success),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProduct,
-// implementedInApiVersion,
-// nameOf(getProduct),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE",
-// "Get Bank Product",
-// s"""Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including:
-// |
-// |* Name
-// |* Code
-// |* Parent Product Code
-// |* More info URL
-// |* Description
-// |* Terms and Conditions
-// |* Description
-// |* Meta
-// |* Attributes
-// |* Fees
-// |
-// |The combination of bank_id and product_code is unique.
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(
-// productCode
-// ) :: Nil JsonGet _ => { cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (product, callContext) <- NewStyle.function.getProduct(
-// bankId,
-// productCode,
-// callContext
-// )
-// (productAttributes, callContext) <- NewStyle.function
-// .getProductAttributesByBankAndCode(
-// bankId,
-// productCode,
-// callContext
-// )
-//
-// (productFees, callContext) <- NewStyle.function
-// .getProductFeesFromProvider(bankId, productCode, callContext)
-//
-// } yield {
-// (
-// JSONFactory400.createProductJson(
-// product,
-// productAttributes,
-// productFees
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomerMessage,
-// implementedInApiVersion,
-// nameOf(createCustomerMessage),
-// "POST",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/messages",
-// "Create Customer Message",
-// s"""
-// |Create a message for the customer specified by CUSTOMER_ID
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// createMessageJsonV400,
-// successMessage,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound
-// ),
-// List(apiTagMessage, apiTagCustomer, apiTagPerson),
-// Some(List(canCreateCustomerMessage))
-// )
-//
-// lazy val createCustomerMessage: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "customers" :: customerId :: "messages" :: Nil JsonPost json -> _ => {
-// cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $CreateMessageJsonV400 "
-// postedData <- NewStyle.function.tryons(
-// failMsg,
-// 400,
-// callContext
-// ) {
-// json.extract[CreateMessageJsonV400]
-// }
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, callContext)
-// (_, callContext) <- NewStyle.function.createCustomerMessage(
-// customer,
-// bankId,
-// postedData.transport,
-// postedData.message,
-// postedData.from_department,
-// postedData.from_person,
-// callContext
-// )
-// } yield {
-// (successMessage, HttpCode.`201`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerMessages,
-// implementedInApiVersion,
-// nameOf(getCustomerMessages),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/messages",
-// "Get Customer Messages for a Customer",
-// s"""Get messages for the customer specified by CUSTOMER_ID
-// ${userAuthenticationMessage(true)}
-// """,
-// EmptyBody,
-// customerMessagesJsonV400,
-// List(AuthenticatedUserIsRequired, $BankNotFound, UnknownError),
-// List(apiTagMessage, apiTagCustomer),
-// Some(List(canGetCustomerMessages))
-// )
-//
-// lazy val getCustomerMessages: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "customers" :: customerId :: "messages" :: Nil JsonGet _ => {
-// cc =>
-// {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (customer, callContext) <- NewStyle.function
-// .getCustomerByCustomerId(customerId, callContext)
-// (messages, callContext) <- NewStyle.function.getCustomerMessages(
-// customer,
-// bankId,
-// callContext
-// )
-// } yield {
-// (
-// JSONFactory400.createCustomerMessagesJson(messages),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-// }
-//
-// val generalWebHookInfo = s"""
-// |Webhooks are used to call external web services when certain events happen.
-// |
-// |For instance, a webhook can be used to notify an external service if a transaction is created on an account.
-// |
-// |"""
-//
-// val accountNotificationWebhookInfo = s"""
-// |When an account notification webhook fires it will POST to the URL you specify during the creation of the webhook.
-// |
-// |Inside the payload you will find account_id and transaction_id and also user_ids and customer_ids of the Users / Customers linked to the Account.
-// | |
-// |The webhook will POST the following structure to your service:
-// |
-// |{
-// | "event_name": "OnCreateTransaction",
-// | "event_id": "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b1",
-// | "bank_id": "gh.29.uk",
-// | "account_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1",
-// | "transaction_id": "7ca9a7e4-6d02-40e3-a129-0b2bf89de9b1",
-// | "related_entities": [
-// | {
-// | "user_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1",
-// | "customer_ids": ["3ca9a7e4-6d02-40e3-a129-0b2bf89de9b1"]
-// | }
-// | ]
-// |}
-// |
-// |Thus, your service should accept the above POST body structure.
-// |
-// |In this way, your web service can be informed about an event on an account and act accordingly.
-// |
-// |Further information about the account, transaction or related entities can then be retrieved using the standard REST APIs.
-// |"""
-//
-// staticResourceDocs += ResourceDoc(
-// createSystemAccountNotificationWebhook,
-// implementedInApiVersion,
-// nameOf(createSystemAccountNotificationWebhook),
-// "POST",
-// "/web-hooks/account/notifications/on-create-transaction",
-// "Create system level Account Notification Webhook",
-// s"""
-// |Create a notification Webhook that will fire for all accounts on the system.
-// |
-// |$generalWebHookInfo
-// |
-// |$accountNotificationWebhookInfo
-// |
-// |""",
-// accountNotificationWebhookPostJson,
-// systemAccountNotificationWebhookJson,
-// List(UnknownError),
-// apiTagWebhook :: apiTagBank :: Nil,
-// Some(List(canCreateSystemAccountNotificationWebhook))
-// )
-//
-// lazy val createSystemAccountNotificationWebhook: OBPEndpoint = {
-// case "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountNotificationWebhookPostJson]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})",
-// cc = callContext
-// ) {
-// postJson.http_method.equals("POST")
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})",
-// cc = callContext
-// ) {
-// postJson.http_protocol.equals("HTTP/1.1")
-// }
-// onCreateTransaction = ApiTrigger.onCreateTransaction.toString()
-// wh <-
-// SystemAccountNotificationWebhookTrait.systemAccountNotificationWebhook.vend
-// .createSystemAccountNotificationWebhookFuture(
-// userId = u.userId,
-// triggerName = onCreateTransaction,
-// url = postJson.url,
-// httpMethod = postJson.http_method,
-// httpProtocol = postJson.http_protocol
-// ) map {
-// unboxFullOrFail(_, callContext, CreateWebhookError)
-// }
-// } yield {
-// (
-// createSystemLevelAccountWebhookJsonV400(wh),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankAccountNotificationWebhook,
-// implementedInApiVersion,
-// nameOf(createBankAccountNotificationWebhook),
-// "POST",
-// "/banks/BANK_ID/web-hooks/account/notifications/on-create-transaction",
-// "Create bank level Account Notification Webhook",
-// s"""Create a notification Webhook that will fire for all accounts on the specified Bank.
-// |
-// |$generalWebHookInfo
-// |
-// |$accountNotificationWebhookInfo
-// |
-// |""",
-// accountNotificationWebhookPostJson,
-// bankAccountNotificationWebhookJson,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// apiTagWebhook :: apiTagBank :: Nil,
-// Some(List(canCreateAccountNotificationWebhookAtOneBank))
-// )
-//
-// lazy val createBankAccountNotificationWebhook: OBPEndpoint = {
-// case "banks" :: BankId(
-// bankId
-// ) :: "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// failMsg =
-// s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AccountNotificationWebhookPostJson]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})",
-// cc = callContext
-// ) {
-// postJson.http_method.equals("POST")
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg =
-// s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})",
-// cc = callContext
-// ) {
-// postJson.http_protocol.equals("HTTP/1.1")
-// }
-// onCreateTransaction = ApiTrigger.onCreateTransaction.toString()
-// wh <-
-// BankAccountNotificationWebhookTrait.bankAccountNotificationWebhook.vend
-// .createBankAccountNotificationWebhookFuture(
-// bankId = bankId.value,
-// userId = u.userId,
-// triggerName = onCreateTransaction,
-// url = postJson.url,
-// httpMethod = postJson.http_method,
-// httpProtocol = postJson.http_protocol
-// ) map {
-// unboxFullOrFail(_, callContext, CreateWebhookError)
-// }
-// } yield {
-// (
-// createBankLevelAccountWebhookJsonV400(wh),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// }
-//
-// private def checkRoleBankIdExsiting(
-// callContext: Option[CallContext],
-// entitlement: CreateEntitlementJSON
-// ) = {
-// Helper.booleanToFuture(
-// failMsg = s"$BankNotFound Current BANK_ID (${entitlement.bank_id})",
-// cc = callContext
-// ) {
-// entitlement.bank_id.nonEmpty == false || BankX(
-// BankId(entitlement.bank_id),
-// callContext
-// ).map(_._1).isEmpty == false
-// }
-// }
-//
-// private def checkRolesBankIdExsiting(
-// callContext: Option[CallContext],
-// postedData: PostCreateUserWithRolesJsonV400
-// ) = {
-// Future.sequence(
-// postedData.roles.map(checkRoleBankIdExsiting(callContext, _))
-// )
-// }
-//
-// private def addEntitlementToUser(
-// userId: String,
-// entitlement: CreateEntitlementJSON,
-// callContext: Option[CallContext]
-// ) = {
-// Future(
-// Entitlement.entitlement.vend
-// .addEntitlement(entitlement.bank_id, userId, entitlement.role_name)
-// ) map { unboxFull(_) }
-// }
-//
-// private def addEntitlementsToUser(
-// userId: String,
-// postedData: PostCreateUserWithRolesJsonV400,
-// callContext: Option[CallContext]
-// ) = {
-// Future.sequence(
-// postedData.roles.distinct.map(
-// addEntitlementToUser(userId, _, callContext)
-// )
-// )
-// }
-//
-// /** This method will check all the roles the request user already has and the
-// * request roles: It will find the roles the requestUser already have, then
-// * show the error to the developer. (We can not grant the same roles to the
-// * request user twice)
-// */
-// private def assertTargetUserLacksRoles(
-// userId: String,
-// requestedEntitlements: List[CreateEntitlementJSON],
-// callContext: Option[CallContext]
-// ) = {
-// // 1st: get all the entitlements for the user:
-// val userEntitlements =
-// Entitlement.entitlement.vend.getEntitlementsByUserId(userId)
-// val userRoles = userEntitlements
-// .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId)))
-// .getOrElse(List.empty[(String, String)])
-// .toSet
-//
-// val targetRoles = requestedEntitlements
-// .map(entitlement => (entitlement.role_name, entitlement.bank_id))
-// .toSet
-//
-// // 2rd: find the duplicated ones:
-// val duplicatedRoles = userRoles.filter(targetRoles)
-//
-// // 3rd: We can not grant the roles again, so we show the error to the developer.
-// if (duplicatedRoles.size > 0) {
-// val errorMessages =
-// s"$EntitlementAlreadyExists user_id($userId) ${duplicatedRoles.mkString(",")}"
-// Helper.booleanToFuture(errorMessages, cc = callContext) { false }
-// } else
-// Future.successful(Full(()))
-// }
-//
-// /** This method will check all the roles the loggedIn user already has and the
-// * request roles: It will find the not existing roles from the loggedIn user
-// * --> we will show the error to the developer (We can only grant the roles
-// * which the loggedIn User has to the requestUser)
-// */
-// private def assertUserCanGrantRoles(
-// userId: String,
-// requestedEntitlements: List[CreateEntitlementJSON],
-// callContext: Option[CallContext]
-// ) = {
-// // 1st: get all the entitlements for the user:
-// val userEntitlements =
-// Entitlement.entitlement.vend.getEntitlementsByUserId(userId)
-// val userRoles = userEntitlements
-// .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId)))
-// .getOrElse(List.empty[(String, String)])
-// .toSet
-//
-// val targetRoles = requestedEntitlements
-// .map(entitlement => (entitlement.role_name, entitlement.bank_id))
-// .toSet
-//
-// // 2rd: find the roles which the loggedIn user does not have,
-// val roleLacking = targetRoles.filterNot(userRoles)
-//
-// if (roleLacking.size > 0) {
-// val errorMessages =
-// s"$EntitlementCannotBeGranted user_id($userId). The login user does not have the following roles: ${roleLacking
-// .mkString(",")}"
-// Helper.booleanToFuture(errorMessages, cc = callContext) { false }
-// } else
-// Future.successful(Full(()))
-// }
-//
-// private def checkRoleBankIdMapping(
-// callContext: Option[CallContext],
-// entitlement: CreateEntitlementJSON
-// ) = {
-// Helper.booleanToFuture(
-// failMsg =
-// if (ApiRole.valueOf(entitlement.role_name).requiresBankId)
-// EntitlementIsBankRole
-// else EntitlementIsSystemRole,
-// cc = callContext
-// ) {
-// ApiRole
-// .valueOf(entitlement.role_name)
-// .requiresBankId == entitlement.bank_id.nonEmpty
-// }
-// }
-//
-// private def checkRoleBankIdMappings(
-// callContext: Option[CallContext],
-// postedData: PostCreateUserWithRolesJsonV400
-// ) = {
-// Future.sequence(
-// postedData.roles.map(checkRoleBankIdMapping(callContext, _))
-// )
-// }
-//
-// private def checkRoleName(
-// callContext: Option[CallContext],
-// entitlement: CreateEntitlementJSON
-// ) = {
-// Future {
-// tryo {
-// valueOf(entitlement.role_name)
-// }
-// } map {
-// val msg =
-// IncorrectRoleName + entitlement.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted
-// .mkString(", ")
-// x => unboxFullOrFail(x, callContext, msg)
-// }
-// }
-//
-// private def checkRolesName(
-// callContext: Option[CallContext],
-// postJsonBody: PostCreateUserWithRolesJsonV400
-// ) = {
-// Future.sequence(postJsonBody.roles.map(checkRoleName(callContext, _)))
-// }
-//
-// private def grantMultpleAccountAccessToUser(
-// bankId: BankId,
-// accountId: AccountId,
-// user: User,
-// views: List[View],
-// callContext: Option[CallContext]
-// ) = {
-// Future.sequence(
-// views.map(view =>
-// grantAccountAccessToUser(
-// bankId: BankId,
-// accountId: AccountId,
-// user: User,
-// view,
-// callContext: Option[CallContext]
-// )
-// )
-// )
-// }
-//
-// private def getViews(
-// bankId: BankId,
-// accountId: AccountId,
-// postJson: PostCreateUserAccountAccessJsonV400,
-// callContext: Option[CallContext]
-// ) = {
-// Future.sequence(
-// postJson.views.map(view =>
-// getView(
-// bankId: BankId,
-// accountId: AccountId,
-// view: PostViewJsonV400,
-// callContext: Option[CallContext]
-// )
-// )
-// )
-// }
-//
-// private def createDynamicEndpointMethod(
-// bankId: Option[String],
-// json: JValue,
-// cc: CallContext
-// ) = {
-// for {
-// (postedJson, openAPI) <- NewStyle.function.tryons(
-// InvalidJsonFormat + "The request json is not valid OpenAPIV3.0.x or Swagger 2.0.x Please check it in Swagger Editor or similar tools ",
-// 400,
-// cc.callContext
-// ) {
-// // If it is bank level, we manually added /banks/bankId in all the paths:
-// val jsonTweakedPath =
-// DynamicEndpointHelper.addedBankToPath(json, bankId)
-// val swaggerContent = compactRender(jsonTweakedPath)
-//
-// (
-// DynamicEndpointSwagger(swaggerContent),
-// DynamicEndpointHelper.parseSwaggerContent(swaggerContent)
-// )
-// }
-// duplicatedUrl = DynamicEndpointHelper
-// .findExistingDynamicEndpoints(openAPI)
-// .map(kv => s"${kv._1}:${kv._2}")
-// errorMsg = s"""$DynamicEndpointExists Duplicated ${if (
-// duplicatedUrl.size > 1
-// ) "endpoints"
-// else "endpoint"}: ${duplicatedUrl.mkString("; ")}"""
-// _ <- Helper.booleanToFuture(errorMsg, cc = cc.callContext) {
-// duplicatedUrl.isEmpty
-// }
-// dynamicEndpointInfo <- NewStyle.function.tryons(
-// InvalidJsonFormat + "Can not convert to OBP Internal Resource Docs",
-// 400,
-// cc.callContext
-// ) {
-// DynamicEndpointHelper.buildDynamicEndpointInfo(
-// openAPI,
-// "current_request_json_body",
-// bankId
-// )
-// }
-// roles <- NewStyle.function.tryons(
-// InvalidJsonFormat + "Can not generate OBP roles",
-// 400,
-// cc.callContext
-// ) {
-// DynamicEndpointHelper.getRoles(dynamicEndpointInfo)
-// }
-// _ <- NewStyle.function.tryons(
-// InvalidJsonFormat + "Can not generate OBP external Resource Docs",
-// 400,
-// cc.callContext
-// ) {
-// JSONFactory1_4_0.createResourceDocsJson(
-// dynamicEndpointInfo.resourceDocs.toList,
-// false,
-// None
-// )
-// }
-// (dynamicEndpoint, callContext) <- NewStyle.function.createDynamicEndpoint(
-// bankId,
-// cc.userId,
-// postedJson.swaggerString,
-// cc.callContext
-// )
-// _ <- NewStyle.function.tryons(
-// InvalidJsonFormat + s"Can not grant these roles ${roles.toString} ",
-// 400,
-// cc.callContext
-// ) {
-// roles.map(role =>
-// Entitlement.entitlement.vend
-// .addEntitlement(bankId.getOrElse(""), cc.userId, role.toString())
-// )
-// }
-// } yield {
-// val swaggerJson = parse(dynamicEndpoint.swaggerString)
-// val responseJson: JObject = (
-// "bank_id",
-// dynamicEndpoint.bankId
-// ) ~ ("user_id", cc.userId) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson)
-// (responseJson, HttpCode.`201`(callContext))
-// }
-// }
-//}
-//
-//object APIMethods400 {
-// lazy val newStyleEndpoints: List[(String, String)] =
-// Implementations4_0_0.resourceDocs.map { rd =>
-// (rd.partialFunctionName, rd.implementedInApiVersion.toString())
-// }.toList
-//
-//}
-//
\ No newline at end of file
diff --git a/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala b/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala
index 51840cd239..c080bbb728 100644
--- a/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala
+++ b/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala
@@ -8105,6 +8105,11 @@ object Http4s400 {
}
}
+ // Public counterpart of getAllJsonSchemaValidations, registered under its own name so the
+ // /endpoints/... case can carry its own ResourceDoc (see initBatch2ResourceDocs), distinct
+ // from the /management/... variant's. Same underlying route.
+ lazy val getAllJsonSchemaValidationsPublic = getAllJsonSchemaValidations
+
lazy val getAuthenticationTypeValidation: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `prefixPath` / "management" / "authentication-type-validations" / operationId =>
EndpointHelpers.withUser(req) { (_, cc) =>
@@ -8129,6 +8134,11 @@ object Http4s400 {
}
}
+ // Public counterpart of getAllAuthenticationTypeValidations, registered under its own name so
+ // the /endpoints/... case can carry its own ResourceDoc (see initBatch2ResourceDocs), distinct
+ // from the /management/... variant's. Same underlying route.
+ lazy val getAllAuthenticationTypeValidationsPublic = getAllAuthenticationTypeValidations
+
lazy val getConnectorMethod: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `prefixPath` / "management" / "connector-methods" / connectorMethodId =>
EndpointHelpers.withUser(req) { (_, cc) =>
@@ -8411,6 +8421,34 @@ object Http4s400 {
http4sPartialFunction = Some(getAllJsonSchemaValidations)
)
+ // read_json_schema_validation_requires_role gates the public /endpoints/... variant below.
+ // Recovered from the commented-out Lift ResourceDoc that used to live in APIMethods400.scala
+ // (see git history for that file), which declared UserHasMissingRoles in its error list —
+ // so the intent was a role gate, not merely a login gate. The role therefore rides the same
+ // prop as the error entry: off (the default) leaves the route public, on requires
+ // canGetJsonSchemaValidation, which is what the prop's name says and what the
+ // /management/... twin enforces unconditionally.
+ val jsonSchemaValidationRequiresRole: Boolean =
+ APIUtil.getPropsAsBoolValue("read_json_schema_validation_requires_role", false)
+
+ staticResourceDocs += ResourceDoc(
+ implementedInApiVersion,
+ nameOf(getAllJsonSchemaValidationsPublic),
+ "GET",
+ "/endpoints/json-schema-validations",
+ "Get all JSON Schema Validations - public",
+ s"""Get all JSON Schema Validations - public.
+ |
+ |""".stripMargin,
+ EmptyBody,
+ ListResult("json_schema_validations", responseJsonSchema :: Nil),
+ (if (jsonSchemaValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil) :::
+ List(UserHasMissingRoles, InvalidJsonFormat, UnknownError),
+ List(apiTagJsonSchemaValidation),
+ if (jsonSchemaValidationRequiresRole) Some(List(canGetJsonSchemaValidation)) else None,
+ http4sPartialFunction = Some(getAllJsonSchemaValidationsPublic)
+ )
+
staticResourceDocs += ResourceDoc(
implementedInApiVersion,
nameOf(getAuthenticationTypeValidation),
@@ -8448,6 +8486,34 @@ object Http4s400 {
http4sPartialFunction = Some(getAllAuthenticationTypeValidations)
)
+ // read_authentication_type_validation_requires_role gates the public /endpoints/... variant
+ // below. Same reasoning as read_json_schema_validation_requires_role above: the recovered
+ // Lift doc declared UserHasMissingRoles, so the role rides the prop rather than the route
+ // being merely login-gated when the prop is on.
+ val authenticationTypeValidationRequiresRole: Boolean =
+ APIUtil.getPropsAsBoolValue("read_authentication_type_validation_requires_role", false)
+
+ staticResourceDocs += ResourceDoc(
+ implementedInApiVersion,
+ nameOf(getAllAuthenticationTypeValidationsPublic),
+ "GET",
+ "/endpoints/authentication-type-validations",
+ "Get all Authentication Type Validations - public",
+ s"""Get all Authentication Type Validations - public.
+ |
+ |""".stripMargin,
+ EmptyBody,
+ ListResult(
+ "authentication_types_validations",
+ List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes))
+ ),
+ (if (authenticationTypeValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil) :::
+ List(UserHasMissingRoles, InvalidJsonFormat, UnknownError),
+ List(apiTagAuthenticationTypeValidation),
+ if (authenticationTypeValidationRequiresRole) Some(List(canGetAuthenticationTypeValidation)) else None,
+ http4sPartialFunction = Some(getAllAuthenticationTypeValidationsPublic)
+ )
+
staticResourceDocs += ResourceDoc(
implementedInApiVersion,
nameOf(getConnectorMethod),
@@ -11163,7 +11229,6 @@ object Http4s400 {
lazy val createTransactionRequestRefund = createTransactionRequest
lazy val createTransactionRequestSepa = createTransactionRequest
lazy val createTransactionRequestSimple = createTransactionRequest
- lazy val getAllAuthenticationTypeValidationsPublic = getAllAuthenticationTypeValidations
// ─── path-rewriting bridge: /obp/v4.0.0/… → /obp/v3.1.0/… ──────────────
diff --git a/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala b/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala
deleted file mode 100644
index 0fe9466889..0000000000
--- a/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
-Open Bank Project - API
-Copyright (C) 2011-2019, TESOBE GmbH.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
-Email: contact@tesobe.com
-TESOBE GmbH.
-Osloer Strasse 16/17
-Berlin 13359, Germany
-
-This product includes software developed at
-TESOBE (http://www.tesobe.com/)
-
- */
-package code.api.v4_0_0
-
-import scala.language.reflectiveCalls
-import code.api.OBPRestHelper
-import code.api.util.VersionedOBPApis
-import code.api.v3_1_0.OBPAPI3_1_0
-import code.util.Helper.MdcLoggable
-import com.github.dwickern.macros.NameOf.nameOf
-import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
-
-/*
-This file defines which endpoints from all the versions are available in v4.0.0.
-All v4.0.0 endpoints have been migrated to Http4s400 — this object is retained
-only for resource-doc aggregation and the Lift dispatch registry.
- */
-object OBPAPI4_0_0 extends OBPRestHelper with MdcLoggable with VersionedOBPApis {
-
- val version: ApiVersion = ApiVersion.v4_0_0
- lazy val versionStatus = ApiVersionStatus.STABLE.toString
-
- // Re-export so any caller that still imports OBPAPI4_0_0.Implementations4_0_0 keeps compiling.
- val Implementations4_0_0 = Http4s400.Implementations4_0_0
-
- lazy val excludeEndpoints =
- nameOf(OBPAPI3_1_0.Implementations1_2_1.addPermissionForUserForBankAccountForMultipleViews) ::
- nameOf(OBPAPI3_1_0.Implementations1_2_1.removePermissionForUserForBankAccountForAllViews) ::
- nameOf(OBPAPI3_1_0.Implementations1_2_1.addPermissionForUserForBankAccountForOneView) ::
- nameOf(OBPAPI3_1_0.Implementations1_2_1.removePermissionForUserForBankAccountForOneView) ::
- nameOf(OBPAPI3_1_0.Implementations3_1_0.createAccount) ::
- nameOf(OBPAPI3_1_0.Implementations3_1_0.revokeConsent) ::
- Nil
-
- def allResourceDocs = collectResourceDocs(
- OBPAPI3_1_0.allResourceDocs,
- Http4s400.resourceDocs
- ).filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|")))
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
- // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here.
-}
diff --git a/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala b/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala
deleted file mode 100644
index f5a3ae64c2..0000000000
--- a/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala
+++ /dev/null
@@ -1,2536 +0,0 @@
-package code.api.v5_0_0
-
-/**
- * All v5.0.0 Lift endpoints have been migrated to Http4s500.
- * This stub is kept so that existing test files that import
- * APIMethods500.Implementations5_0_0 continue to compile.
- */
-object APIMethods500 {
- val Implementations5_0_0 = Http4s500.Implementations5_0_0
-}
-
-trait APIMethods500
-
-// ─── Original Lift implementation (commented out) ────────────────────────────
-//package code.api.v5_0_0
-//
-//import scala.language.reflectiveCalls
-//import code.accountattribute.AccountAttributeX
-//import code.api.Constant._
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
-//import code.api.util.APIUtil._
-//import code.api.util.ApiRole._
-//import code.api.util.ApiTag._
-//import code.api.util.ErrorMessages._
-//import code.api.util.FutureUtil.EndpointContext
-//import code.api.util.NewStyle.HttpCode
-//import code.api.util.NewStyle.function.extractQueryParams
-//import code.api.util._
-//import code.api.util.newstyle.ViewNewStyle
-//import code.api.v2_1_0.JSONFactory210
-//import code.api.v3_0_0.JSONFactory300
-//import code.api.v3_1_0._
-//import code.api.v4_0_0.JSONFactory400.createCustomersMinimalJson
-//import code.api.v4_0_0.{JSONFactory400, PostCounterpartyJson400}
-//import code.api.v5_0_0.JSONFactory500.{createPhysicalCardJson, createViewJsonV500, createViewsIdsJsonV500, createViewsJsonV500}
-//import code.api.v5_1_0.{CreateCustomViewJson, PostCounterpartyLimitV510, PostVRPConsentRequestJsonV510}
-//import code.bankconnectors.Connector
-//import code.consent.{ConsentRequests, ConsentStatus, Consents, MappedConsent}
-//import code.consumer.Consumers
-//import code.entitlement.Entitlement
-//import code.metadata.counterparties.MappedCounterparty
-//import code.metrics.APIMetrics
-//import code.model.dataAccess.BankAccountCreation
-//import code.util.Helper
-//import code.util.Helper.{SILENCE_IS_GOLDEN, booleanToFuture}
-//import code.views.Views
-//import com.github.dwickern.macros.NameOf.nameOf
-//import com.openbankproject.commons.ExecutionContext.Implicits.global
-//import com.openbankproject.commons.model._
-//import com.openbankproject.commons.model.enums.StrongCustomerAuthentication
-//import com.openbankproject.commons.util.ApiVersion
-//import net.liftweb.common.{Empty, Full}
-//import com.openbankproject.commons.util.json
-//import org.json4s.{Extraction, compactRender, prettyRender}
-//import net.liftweb.mapper.By
-//import net.liftweb.util.Helpers.tryo
-//import net.liftweb.util.{Helpers, Props, StringHelpers}
-//
-//import java.util.UUID
-//import java.util.concurrent.ThreadLocalRandom
-//import scala.collection.immutable.{List, Nil}
-//import scala.collection.mutable.ArrayBuffer
-//import scala.concurrent.Future
-//import scala.util.Random
-//
-//trait APIMethods500 {
-// self: RestHelper =>
-//
-// val Implementations5_0_0 = new Implementations500()
-//
-// protected trait TestHead {
-// /**
-// * Test to see if the request is a GET and expecting JSON in the response.
-// * The path and the Req instance are extracted.
-// */
-// def unapply(r: Req): Option[(List[String], Req)] =
-// if (r.requestType.head_? && testResponse_?(r))
-// Some(r.path.partPath -> r) else None
-//
-// def testResponse_?(r: Req): Boolean
-// }
-//
-// lazy val JsonHead = new TestHead with JsonTest
-//
-// class Implementations500 {
-//
-// val implementedInApiVersion = ApiVersion.v5_0_0
-//
-// private val staticResourceDocs = ArrayBuffer[ResourceDoc]()
-// def resourceDocs = staticResourceDocs
-//
-// val apiRelations = ArrayBuffer[ApiRelation]()
-// val codeContext = CodeContext(staticResourceDocs, apiRelations)
-//
-//
-// staticResourceDocs += ResourceDoc(
-// root,
-// implementedInApiVersion,
-// "root",
-// "GET",
-// "/root",
-// "Get API Info (root)",
-// """Returns information about:
-// |
-// |* API version
-// |* Hosted by information
-// |* Hosted at information
-// |* Energy source information
-// |* Git Commit""",
-// EmptyBody,
-// apiInfoJson400,
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil)
-//
-// lazy val root: OBPEndpoint = {
-// case (Nil | "root" :: Nil) JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (JSONFactory400.getApiInfoJSON(OBPAPI5_0_0.version,OBPAPI5_0_0.versionStatus), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBank,
-// implementedInApiVersion,
-// nameOf(getBank),
-// "GET",
-// "/banks/BANK_ID",
-// "Get Bank",
-// """Get the bank specified by BANK_ID
-// |Returns information about a single bank specified by BANK_ID including:
-// |
-// |* Bank code and full name of bank
-// |* Logo URL
-// |* Website""",
-// EmptyBody,
-// bankJson500,
-// List(UnknownError, BankNotFound),
-// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBank : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (bank, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (attributes, callContext) <- NewStyle.function.getBankAttributesByBank(bankId, callContext)
-// } yield
-// (JSONFactory500.createBankJSON500(bank, attributes), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBank,
-// implementedInApiVersion,
-// "createBank",
-// "POST",
-// "/banks",
-// "Create Bank",
-// s"""Create a new bank (Authenticated access).
-// |
-// |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.
-// |Thus the User can manage the bank they create and assign Roles to other Users.
-// |
-// |Only SANDBOX mode (i.e. when connector=mapped in properties file)
-// |The settlement accounts are automatically created by the system when the bank is created.
-// |Name and account id are created in accordance to the next rules:
-// | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)
-// | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)
-// |
-// |""",
-// postBankJson500,
-// bankJson500,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// InsufficientAuthorisationToCreateBank,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canCreateBank))
-// )
-//
-// lazy val createBank: OBPEndpoint = {
-// case "banks" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostBankJson500 "
-// for {
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostBankJson500]
-// }
-//
-// //if postJson.id is empty, just return SILENCE_IS_GOLDEN, and will pass the guard.
-// checkShortStringValue = APIUtil.checkOptionalShortString(postJson.id.getOrElse(SILENCE_IS_GOLDEN))
-// _ <- Helper.booleanToFuture(failMsg = s"$checkShortStringValue.", cc = cc.callContext) {
-// checkShortStringValue == SILENCE_IS_GOLDEN
-// }
-//
-// _ <- Helper.booleanToFuture(failMsg = ErrorMessages.InvalidConsumerCredentials, cc=cc.callContext) {
-// cc.callContext.map(_.consumer.isDefined == true).isDefined
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", cc=cc.callContext) {
-// postJson.id.forall(_.length > 3)
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain space characters", cc=cc.callContext) {
-// !postJson.id.contains(" ")
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain `::::` characters", cc=cc.callContext) {
-// !`checkIfContains::::`(postJson.id.getOrElse(""))
-// }
-// (banks, callContext) <- NewStyle.function.getBanks(cc.callContext)
-// _ <- Helper.booleanToFuture(failMsg = ErrorMessages.bankIdAlreadyExists, cc=cc.callContext) {
-// !banks.exists { b => Some(b.bankId.value) == postJson.id }
-// }
-// (success, callContext) <- NewStyle.function.createOrUpdateBank(
-// postJson.id.getOrElse(APIUtil.generateUUID()),
-// postJson.full_name.getOrElse(""),
-// postJson.bank_code,
-// postJson.logo.getOrElse(""),
-// postJson.website.getOrElse(""),
-// postJson.bank_routings.getOrElse(Nil).find(_.scheme == "BIC").map(_.address).getOrElse(""),
-// "",
-// postJson.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.scheme).getOrElse(""),
-// postJson.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.address).getOrElse(""),
-// callContext
-// )
-// entitlements <- NewStyle.function.getEntitlementsByUserId(cc.userId, callContext)
-// entitlementsByBank = entitlements.filter(_.bankId==postJson.id.getOrElse(""))
-// _ <- entitlementsByBank.filter(_.roleName == CanCreateEntitlementAtOneBank.toString()).size > 0 match {
-// case true =>
-// // Already has entitlement
-// Future(())
-// case false =>
-// Future(Entitlement.entitlement.vend.addEntitlement(postJson.id.getOrElse(""), cc.userId, CanCreateEntitlementAtOneBank.toString()))
-// }
-// _ <- entitlementsByBank.filter(_.roleName == CanReadDynamicResourceDocsAtOneBank.toString()).size > 0 match {
-// case true =>
-// // Already has entitlement
-// Future(())
-// case false =>
-// Future(Entitlement.entitlement.vend.addEntitlement(postJson.id.getOrElse(""), cc.userId, CanReadDynamicResourceDocsAtOneBank.toString()))
-// }
-// } yield {
-// (JSONFactory500.createBankJSON500(success), HttpCode.`201`(callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// updateBank,
-// implementedInApiVersion,
-// "updateBank",
-// "PUT",
-// "/banks",
-// "Update Bank",
-// s"""Update an existing bank (Authenticated access).
-// |
-// |""",
-// postBankJson500,
-// bankJson500,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// BankNotFound,
-// updateBankError,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canCreateBank))
-// )
-//
-// lazy val updateBank: OBPEndpoint = {
-// case "banks" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostBankJson500 "
-// for {
-// bank <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostBankJson500]
-// }
-// _ <- Helper.booleanToFuture(failMsg = ErrorMessages.InvalidConsumerCredentials, cc=cc.callContext) {
-// cc.callContext.map(_.consumer.isDefined == true).isDefined
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", cc=cc.callContext) {
-// bank.id.forall(_.length > 3)
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain space characters", cc=cc.callContext) {
-// !bank.id.contains(" ")
-// }
-// bankId <- NewStyle.function.tryons(ErrorMessages.updateBankError, 400, cc.callContext) {
-// bank.id.get
-// }
-// (_, callContext) <- NewStyle.function.getBank(BankId(bankId), cc.callContext)
-// (success, callContext) <- NewStyle.function.createOrUpdateBank(
-// bankId,
-// bank.full_name.getOrElse(""),
-// bank.bank_code,
-// bank.logo.getOrElse(""),
-// bank.website.getOrElse(""),
-// bank.bank_routings.getOrElse(Nil).find(_.scheme == "BIC").map(_.address).getOrElse(""),
-// "",
-// bank.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.scheme).getOrElse(""),
-// bank.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.address).getOrElse(""),
-// callContext
-// )
-// } yield {
-// (JSONFactory500.createBankJSON500(success), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// createAccount,
-// implementedInApiVersion,
-// "createAccount",
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID",
-// "Create Account (PUT)",
-// """Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.
-// |
-// |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.
-// |
-// |If the PUT body USER_ID *is* specified, the logged in user must have the Role canCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.
-// |
-// |If the PUT body USER_ID is *not* specified, the account will be owned by the logged in User.
-// |
-// |The 'product_code' field SHOULD be a product_code from Product.
-// |If the 'product_code' matches a product_code from Product, account attributes will be created that match the Product Attributes.
-// |
-// |Note: The Amount MUST be zero.""".stripMargin,
-// createAccountRequestJsonV500,
-// createAccountResponseJsonV310,
-// List(
-// InvalidJsonFormat,
-// BankNotFound,
-// AuthenticatedUserIsRequired,
-// InvalidUserId,
-// InvalidAccountIdFormat,
-// InvalidBankIdFormat,
-// UserNotFoundById,
-// UserHasMissingRoles,
-// InvalidAccountBalanceAmount,
-// InvalidAccountInitialBalance,
-// InitialBalanceMustBeZero,
-// InvalidAccountBalanceCurrency,
-// AccountIdAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagAccount,apiTagOnboarding),
-// Some(List(canCreateAccount))
-// )
-//
-//
-// lazy val createAccount : OBPEndpoint = {
-// // Create a new account
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: Nil JsonPut json -> _ => {
-// cc =>{
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (account, callContext) <- Connector.connector.vend.checkBankAccountExists(bankId, accountId, callContext)
-// _ <- Helper.booleanToFuture(AccountIdAlreadyExists, cc=callContext){
-// account.isEmpty
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} "
-// createAccountJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[CreateAccountRequestJsonV500]
-// }
-// loggedInUserId = u.userId
-// userIdAccountOwner = createAccountJson.user_id match {
-// case Some(userId) => userId
-// case _ => loggedInUserId
-// }
-// _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// (postedOrLoggedInUser,callContext) <- NewStyle.function.findByUserId(userIdAccountOwner, callContext)
-// // User can create account for self or an account for another user if they have CanCreateAccount role
-// _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){
-// isValidID(accountId.value)
-// }
-// _ <- {userIdAccountOwner == loggedInUserId} match {
-// case true => Future.successful(Full(Unit))
-// case false =>
-// NewStyle.function.hasEntitlement(
-// bankId.value,
-// loggedInUserId,
-// canCreateAccount,
-// callContext,
-// s"${UserHasMissingRoles} $canCreateAccount or create account for self"
-// )
-// }
-// initialBalanceAsString = createAccountJson.balance.map(_.amount).getOrElse("0")
-// accountType = createAccountJson.product_code
-// accountLabel = createAccountJson.label
-// initialBalanceAsNumber <- NewStyle.function.tryons(InvalidAccountInitialBalance, 400, callContext) {
-// BigDecimal(initialBalanceAsString)
-// }
-// _ <- Helper.booleanToFuture(InitialBalanceMustBeZero, cc=callContext){0 == initialBalanceAsNumber}
-// _ <- Helper.booleanToFuture(InvalidISOCurrencyCode, cc=callContext){isValidCurrencyISOCode(createAccountJson.balance.map(_.currency).getOrElse("EUR"))}
-// currency = createAccountJson.balance.map(_.currency).getOrElse("EUR")
-// (_, callContext ) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- Helper.booleanToFuture(s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", 400, cc=callContext){
-// createAccountJson.account_routings.getOrElse(Nil).map(_.scheme).distinct.size == createAccountJson.account_routings.getOrElse(Nil).size
-// }
-// alreadyExistAccountRoutings <- Future.sequence(createAccountJson.account_routings.getOrElse(Nil).map(accountRouting =>
-// NewStyle.function.getAccountRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
-// ))
-// alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
-// case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
-// }
-// _ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", cc=callContext) {
-// alreadyExistingAccountRouting.isEmpty
-// }
-// (bankAccount,callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// accountId,
-// accountType,
-// accountLabel,
-// currency,
-// initialBalanceAsNumber,
-// postedOrLoggedInUser.name,
-// createAccountJson.branch_id.getOrElse(""),
-// createAccountJson.account_routings.getOrElse(Nil).map(r => AccountRouting(r.scheme, r.address)),
-// callContext
-// )
-// (productAttributes, callContext) <- NewStyle.function.getProductAttributesByBankAndCode(bankId, ProductCode(accountType), callContext)
-// (accountAttributes, callContext) <- NewStyle.function.createAccountAttributes(
-// bankId,
-// accountId,
-// ProductCode(accountType),
-// productAttributes,
-// None,
-// callContext: Option[CallContext]
-// )
-// //1 Create or Update the `Owner` for the new account
-// //2 Add permission to the user
-// //3 Set the user as the account holder
-// _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(bankId, accountId, postedOrLoggedInUser, callContext)
-// } yield {
-// (JSONFactory310.createAccountJSON(userIdAccountOwner, bankAccount, accountAttributes), HttpCode.`201`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createUserAuthContext,
-// implementedInApiVersion,
-// nameOf(createUserAuthContext),
-// "POST",
-// "/users/USER_ID/auth-context",
-// "Create User Auth Context",
-// s"""Create User Auth Context. These key value pairs will be propagated over connector to adapter. Normally used for mapping OBP user and
-// | Bank User/Customer.
-// |${userAuthenticationMessage(true)}
-// |""",
-// postUserAuthContextJson,
-// userAuthContextJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// CreateUserAuthContextError,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canCreateUserAuthContext)))
-// lazy val createUserAuthContext : OBPEndpoint = {
-// case "users" :: userId ::"auth-context" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateUserAuthContext, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextJson]
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key.trim, postedData.value.trim, callContext)
-// } yield {
-// (JSONFactory500.createUserAuthContextJson(userAuthContext), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getUserAuthContexts,
-// implementedInApiVersion,
-// nameOf(getUserAuthContexts),
-// "GET",
-// "/users/USER_ID/auth-context",
-// "Get User Auth Contexts",
-// s"""Get User Auth Contexts for a User.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// userAuthContextJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(canGetUserAuthContext :: Nil)
-// )
-// lazy val getUserAuthContexts : OBPEndpoint = {
-// case "users" :: userId :: "auth-context" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetUserAuthContext, callContext)
-// (_, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// (userAuthContexts, callContext) <- NewStyle.function.getUserAuthContexts(userId, callContext)
-// } yield {
-// (JSONFactory500.createUserAuthContextsJson(userAuthContexts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUserAuthContextUpdateRequest,
-// implementedInApiVersion,
-// nameOf(createUserAuthContextUpdateRequest),
-// "POST",
-// "/banks/BANK_ID/users/current/auth-context-updates/SCA_METHOD",
-// "Create User Auth Context Update Request",
-// s"""Create User Auth Context Update Request.
-// |${userAuthenticationMessage(true)}
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS" or "EMAIL". "EMAIL" is used for testing purposes.
-// |
-// |""",
-// postUserAuthContextJson,
-// userAuthContextUpdateJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CreateUserAuthContextError,
-// UnknownError
-// ),
-// List(apiTagUser),
-// None
-// )
-//
-// lazy val createUserAuthContextUpdateRequest : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: scaMethod :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanCreateUserAuthContextUpdate, cc=callContext) {
-// checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate)
-// }
-// _ <- Helper.booleanToFuture(UserAuthContextUpdateRequestAllowedScaMethods, cc=callContext){
-// List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextJson]
-// }
-// (userAuthContextUpdate, callContext) <- NewStyle.function.validateUserAuthContextUpdateRequest(bankId.value, user.userId, postedData.key.trim, postedData.value.trim, scaMethod, callContext)
-// } yield {
-//
-// (JSONFactory500.createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// answerUserAuthContextUpdateChallenge,
-// implementedInApiVersion,
-// nameOf(answerUserAuthContextUpdateChallenge),
-// "POST",
-// "/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge",
-// "Answer User Auth Context Update Challenge",
-// s"""
-// |Answer User Auth Context Update Challenge.
-// |""",
-// postUserAuthContextUpdateJsonV310,
-// userAuthContextUpdateJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagUser :: Nil)
-//
-// lazy val answerUserAuthContextUpdateChallenge : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: authContextUpdateId :: "challenge" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextUpdateJsonV310 "
-// postUserAuthContextUpdateJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostUserAuthContextUpdateJsonV310]
-// }
-// (userAuthContextUpdate, callContext) <- NewStyle.function.checkAnswer(authContextUpdateId, postUserAuthContextUpdateJson.answer, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userAuthContextUpdate.userId, callContext)
-// (_, callContext) <-
-// userAuthContextUpdate.status match {
-// case status if status == UserAuthContextUpdateStatus.ACCEPTED.toString =>
-// NewStyle.function.createUserAuthContext(
-// user,
-// userAuthContextUpdate.key.trim,
-// userAuthContextUpdate.value.trim,
-// callContext).map(x => (Some(x._1), x._2))
-// case _ =>
-// Future((None, callContext))
-// }
-// (_, callContext) <-
-// userAuthContextUpdate.key match {
-// case "CUSTOMER_NUMBER" =>
-// NewStyle.function.getOCreateUserCustomerLink(
-// bankId,
-// userAuthContextUpdate.value, // Customer number
-// user.userId,
-// callContext
-// )
-// case _ =>
-// Future((None, callContext))
-// }
-// } yield {
-// (JSONFactory500.createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createConsentRequest,
-// implementedInApiVersion,
-// nameOf(createConsentRequest),
-// "POST",
-// "/consumer/consent-requests",
-// "Create Consent Request",
-// s"""
-// |Create a Consent Request — the first step of the OBP Consent flow.
-// |
-// |The calling application (TPP) authenticates with Client Credentials and posts the consent details (entitlements, account_access, VRP fields, etc.). The User then completes the flow by calling Create Consent By CONSENT_REQUEST_ID.
-// |
-// |The Consent Request is recorded against the calling consumer (its creator).
-// |
-// |Optional body fields of note:
-// |
-// |- `consumer_id`: if set, the resulting Consent (created when the User answers this request) will be pinned to this consumer instead of the creator. Use only when the consent is intended for a different application than the one creating the request. Most TPPs should omit this field — when omitted, the resulting Consent is pinned to the creator. Note: this override is being deprecated; v6.0.0 will pin the resulting Consent to the creator unconditionally.
-// |- `email` / `phone_number`: surface in the SCA challenge if the User chooses EMAIL or SMS at answer time.
-// |- `valid_from` / `time_to_live`: control the lifetime of the resulting Consent.
-// |
-// |Authentication:
-// |
-// |The client needs to authenticate themselves for this request. In case of public client we use client_id and private key to obtain access token; otherwise we use client_id and client_secret. The obtained access token is used in the HTTP Bearer auth header of our request.
-// |
-// |Example:
-// |Authorization: Bearer eXtneO-THbQtn3zvK_kQtXXfvOZyZFdBCItlPDbR2Bk.dOWqtXCtFX-tqGTVR0YrIjvAolPIVg7GZ-jz83y6nA0
-// |
-// |After successfully creating the Consent Request, call Create Consent By CONSENT_REQUEST_ID to finalize.
-// |
-// |See Glossary entry "Authentication: Consent OBP Flow Example" for an end-to-end walk-through.
-// |
-// |${applicationAccessMessage(true)}
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |
-// |""".stripMargin,
-// postConsentRequestJsonV500,
-// consentRequestResponseJson,
-// List(
-// InvalidJsonFormat,
-// ConsentMaxTTL,
-// X509CannotGetCertificate,
-// X509GeneralError,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val createConsentRequest : OBPEndpoint = {
-// case "consumer" :: "consent-requests" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- applicationAccess(cc)
-// _ <- passesPsd2Aisp(callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
-// consentJson: PostConsentRequestJsonV500 <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentRequestJsonV500]
-// }
-// maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
-// _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){
-// consentJson.time_to_live match {
-// case Some(ttl) => ttl <= maxTimeToLive
-// case _ => true
-// }
-// }
-// createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.createConsentRequest(
-// callContext.flatMap(_.consumer),
-// Some(compactRender(json))
-// )) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (JSONFactory500.createConsentRequestResponseJson(createdConsentRequest), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentRequest,
-// implementedInApiVersion,
-// nameOf(getConsentRequest),
-// "GET",
-// "/consumer/consent-requests/CONSENT_REQUEST_ID",
-// "Get Consent Request",
-// s"""
-// |Return the full payload of a previously-created Consent Request — the JSON the TPP submitted to Create Consent Request, plus the consent_request_id and the creating consumer_id.
-// |
-// |Use this endpoint to verify the contents of a Consent Request before the User answers it.
-// |
-// |Authentication: Application access (any registered consumer/application can read any Consent Request by ID).
-// |
-// |Note: this endpoint will be restricted to the creating consumer in v6.0.0. Until then, treat CONSENT_REQUEST_IDs as sensitive — they reveal entitlements, account routings, and contact details (email/phone) submitted at creation.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// consentRequestResponseJson,
-// List(
-// InvalidJsonFormat,
-// ConsentMaxTTL,
-// X509CannotGetCertificate,
-// X509GeneralError,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getConsentRequest : OBPEndpoint = {
-// case "consumer" :: "consent-requests" :: consentRequestId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- applicationAccess(cc)
-// _ <- passesPsd2Aisp(callContext)
-// createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.getConsentRequestById(
-// consentRequestId
-// )) map {
-// i => unboxFullOrFail(i,callContext, ConsentRequestNotFound)
-// }
-// } yield {
-// (JSONFactory500.createConsentRequestResponseJson(createdConsentRequest), HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentByConsentRequestId,
-// implementedInApiVersion,
-// nameOf(getConsentByConsentRequestId),
-// "GET",
-// "/consumer/consent-requests/CONSENT_REQUEST_ID/consents",
-// "Get Consent By Consent Request Id via Consumer",
-// s"""
-// |
-// |This endpoint gets the Consent By consent request id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-// lazy val getConsentByConsentRequestId: OBPEndpoint = {
-// case "consumer" :: "consent-requests" :: consentRequestId :: "consents" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- applicationAccess(cc)
-// consent <- Future { Consents.consentProvider.vend.getConsentByConsentRequestId(consentRequestId)} map {
-// unboxFullOrFail(_, callContext, ConsentRequestNotFound)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, failCode = 404, cc = cc.callContext) {
-// consent.mConsumerId.get == cc.consumer.map(_.consumerId.get).getOrElse("None")
-// }
-// (bankId, accountId, viewId, helperInfo) <- NewStyle.function.tryons(failMsg = Oauth2BadJWTException, 400, callContext) {
-// val jsonWebTokenAsJValue = JwtUtil.getSignedPayloadAsJson(consent.jsonWebToken).map(json.parse(_).extract[ConsentJWT])
-// val viewsFromJwtToken = jsonWebTokenAsJValue.head.views
-// //at the moment,we only support VRP consent to show `ConsentAccountAccessJson` in the response. Because the TPP need them for payments.
-// val isVrpConsent = (viewsFromJwtToken.length == 1 )&& (viewsFromJwtToken.head.bank_id.nonEmpty)&& (viewsFromJwtToken.head.account_id.nonEmpty)&& (viewsFromJwtToken.head.view_id.startsWith("_vrp-"))
-//
-// if(isVrpConsent){
-// val bankId = BankId(viewsFromJwtToken.head.bank_id)
-// val accountId = AccountId(viewsFromJwtToken.head.account_id)
-// val viewId = ViewId(viewsFromJwtToken.head.view_id)
-// val helperInfoFromJwtToken = viewsFromJwtToken.head.helper_info
-// val viewCanGetCounterparty = Views.views.vend.customView(viewId, BankIdAccountId(bankId, accountId)).map(_.allowed_actions.exists( _ == CAN_GET_COUNTERPARTY))
-// val helperInfo = if(viewCanGetCounterparty==Full(true)) helperInfoFromJwtToken else None
-// (Some(bankId), Some(accountId), Some(viewId), helperInfo)
-// }else{
-// (None, None, None, None)
-// }
-// }
-// } yield {
-// (
-// ConsentJsonV500(
-// consent.consentId,
-// consent.jsonWebToken,
-// consent.status,
-// Some(consent.consentRequestId),
-// if (bankId.isDefined && accountId.isDefined && viewId.isDefined) {
-// Some(ConsentAccountAccessJson(
-// bank_id = bankId.get.value,
-// account_id = accountId.get.value,
-// view_id = viewId.get.value,
-// helper_info = helperInfo
-// ))
-// } else {
-// None
-// }
-// ),
-// HttpCode.`200`(cc)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createConsentByConsentRequestIdEmail,
-// implementedInApiVersion,
-// nameOf(createConsentByConsentRequestIdEmail),
-// "POST",
-// "/consumer/consent-requests/CONSENT_REQUEST_ID/EMAIL/consents",
-// "Create Consent By CONSENT_REQUEST_ID (EMAIL)",
-// s"""
-// |Answer a Consent Request and create the resulting Consent, with an EMAIL Strong Customer Authentication challenge.
-// |
-// |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).
-// |
-// |An SCA challenge code is sent to the email address that was supplied in the Create Consent Request body. The User then completes SCA via Answer Consent Challenge, which moves the Consent from INITIATED to ACCEPTED.
-// |
-// |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).
-// |
-// |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.
-// |
-// |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.
-// |
-// |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.
-// |
-// |""",
-// EmptyBody,
-// consentJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: apiTagVrp :: Nil)
-//
-// staticResourceDocs += ResourceDoc(
-// createConsentByConsentRequestIdSms,
-// implementedInApiVersion,
-// nameOf(createConsentByConsentRequestIdSms),
-// "POST",
-// "/consumer/consent-requests/CONSENT_REQUEST_ID/SMS/consents",
-// "Create Consent By CONSENT_REQUEST_ID (SMS)",
-// s"""
-// |Answer a Consent Request and create the resulting Consent, with an SMS Strong Customer Authentication challenge.
-// |
-// |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).
-// |
-// |An SCA challenge code is sent to the phone number that was supplied in the Create Consent Request body. The User then completes SCA via Answer Consent Challenge, which moves the Consent from INITIATED to ACCEPTED.
-// |
-// |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).
-// |
-// |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.
-// |
-// |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.
-// |
-// |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.
-// |
-// |""",
-// EmptyBody,
-// consentJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// ConsentRequestIsInvalid,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// MissingPropsValueAtThisInstance,
-// SmsServerNotResponding,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// staticResourceDocs += ResourceDoc(
-// createConsentByConsentRequestIdImplicit,
-// implementedInApiVersion,
-// nameOf(createConsentByConsentRequestIdImplicit),
-// "POST",
-// "/consumer/consent-requests/CONSENT_REQUEST_ID/IMPLICIT/consents",
-// "Create Consent By CONSENT_REQUEST_ID (IMPLICIT)",
-// s"""
-// |Answer a Consent Request and create the resulting Consent, without a Strong Customer Authentication challenge — the Consent is moved directly from INITIATED to ACCEPTED.
-// |
-// |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).
-// |
-// |IMPLICIT means no SCA challenge is sent. The Consent is immediately ACCEPTED. Use only in flows where the User has already been strongly authenticated by upstream means; for production use behind a public TPP, prefer EMAIL or SMS.
-// |
-// |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).
-// |
-// |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.
-// |
-// |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.
-// |
-// |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.
-// |
-// |""",
-// EmptyBody,
-// consentJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// ConsentRequestIsInvalid,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// MissingPropsValueAtThisInstance,
-// SmsServerNotResponding,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// lazy val createConsentByConsentRequestIdEmail = createConsentByConsentRequestId
-// lazy val createConsentByConsentRequestIdSms = createConsentByConsentRequestId
-// lazy val createConsentByConsentRequestIdImplicit = createConsentByConsentRequestId
-//
-// lazy val createConsentByConsentRequestId : OBPEndpoint = {
-//
-// case "consumer" :: "consent-requests":: consentRequestId :: scaMethod :: "consents" :: Nil JsonPost _ -> _ => {
-// def sendEmailNotification(callContext: Option[CallContext], consentRequestJson: PostConsentRequestJsonV500, challengeText: String) = {
-// for {
-// failMsg <- Future {
-// s"$InvalidJsonFormat The Json body must contain the field email"
-// }
-// consentScaEmail <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// consentRequestJson.email.head
-// }
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.EMAIL,
-// consentScaEmail,
-// Some("OBP Consent Challenge"),
-// challengeText,
-// callContext
-// )
-// } yield {
-// status
-// }
-// }
-// def sendSmsNotification(callContext: Option[CallContext], consentRequestJson: PostConsentRequestJsonV500, challengeText: String) = {
-// for {
-// failMsg <- Future {
-// s"$InvalidJsonFormat The Json body must contain the field phone_number"
-// }
-// consentScaPhoneNumber <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// consentRequestJson.phone_number.head
-// }
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.SMS,
-// consentScaPhoneNumber,
-// None,
-// challengeText,
-// callContext
-// )
-// } yield {
-// status
-// }
-// }
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.getConsentRequestById(
-// consentRequestId
-// )) map {
-// i => unboxFullOrFail(i,callContext, ConsentRequestNotFound)
-// }
-// _ <- Helper.booleanToFuture(s"$ConsentRequestIsInvalid, the current CONSENT_REQUEST_ID($consentRequestId) is already used to create a consent, please provide another one!", cc=callContext){
-// Consents.consentProvider.vend.getConsentByConsentRequestId(consentRequestId).isEmpty
-// }
-// _ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
-// List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod)
-// }
-// // If the payload contains "to_account` , it mean it is a VRP consent.
-// isVrpConsent = createdConsentRequest.payload.contains("to_account")
-// (consentRequestJson, isVRPConsentRequest) <-
-// if(isVrpConsent) {
-// val failMsg = s"$InvalidJsonFormat The vrp consent request json body should be the $PostVRPConsentRequestJsonV510 "
-// NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.parse(createdConsentRequest.payload).extract[code.api.v5_1_0.PostVRPConsentRequestJsonInternalV510]
-// }.map(postVRPConsentRequest => (postVRPConsentRequest.toPostConsentRequestJsonV500, true))
-// } else{
-// val failMsg = s"$InvalidJsonFormat The consent request Json body should be the $PostConsentRequestJsonV500 "
-// NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.parse(createdConsentRequest.payload).extract[PostConsentRequestJsonV500]
-// }.map(postVRPConsentRequest => (postVRPConsentRequest, false))
-// }
-//
-// //Here are all the VRP consent request
-// (bankId, accountId, viewId, counterpartyId) <- if (isVRPConsentRequest) {
-// val postConsentRequestJsonV510 = json.parse(createdConsentRequest.payload).extract[code.api.v5_1_0.PostVRPConsentRequestJsonV510]
-//
-// val vrpViewId = s"_vrp-${UUID.randomUUID.toString}".dropRight(5)// to make sure the length of the viewId is 36.
-// val targetPermissions = List(//may need getTransactionRequest . so far only these payments.
-// CAN_ADD_TRANSACTION_REQUEST_TO_BENEFICIARY,
-// CAN_GET_COUNTERPARTY,
-// CAN_SEE_TRANSACTION_REQUESTS,
-// )
-//
-// val targetCreateCustomViewJson = CreateCustomViewJson(
-// name = vrpViewId,
-// description = vrpViewId,
-// metadata_view = vrpViewId,
-// is_public = false,
-// which_alias_to_use = vrpViewId,
-// hide_metadata_if_alias_used = true,
-// allowed_permissions = targetPermissions
-// )
-//
-// val fromBankAccountRoutings = BankAccountRoutings(
-// bank = BankRoutingJson(postConsentRequestJsonV510.from_account.bank_routing.scheme, postConsentRequestJsonV510.from_account.bank_routing.address),
-// account = BranchRoutingJsonV141(postConsentRequestJsonV510.from_account.account_routing.scheme, postConsentRequestJsonV510.from_account.account_routing.address),
-// branch = AccountRoutingJsonV121(postConsentRequestJsonV510.from_account.branch_routing.scheme, postConsentRequestJsonV510.from_account.branch_routing.address)
-// )
-//
-// for {
-// //1st: get the fromAccount by routings:
-// (fromAccount, callContext) <- NewStyle.function.getBankAccountByRoutings(fromBankAccountRoutings, callContext)
-// fromBankIdAccountId = BankIdAccountId(fromAccount.bankId, fromAccount.accountId)
-//
-// //2rd: create the Custom View for the fromAccount.
-// //we do not need sourceViewId so far, we need to get all the view access for the login user, and
-// permission <- NewStyle.function.permission(fromAccount.bankId, fromAccount.accountId, user, callContext)
-// permissionsFromSource = permission.views.map(_.allowed_actions).flatten.toSet
-// permissionsFromTarget = targetCreateCustomViewJson.allowed_permissions
-//
-// //eg: permissionsFromTarget=List(1,2), permissionsFromSource = List(1,3,4) => userMissingPermissions = List(2)
-// //Here would find the missing permissions and show them in the error messages
-// userMissingPermissions = permissionsFromTarget.toSet diff permissionsFromSource
-//
-// failMsg = s"${ErrorMessages.UserDoesNotHavePermission} ${userMissingPermissions.toString}"
-// _ <- Helper.booleanToFuture(failMsg, cc = callContext) {
-// userMissingPermissions.isEmpty
-// }
-// (vrpView, callContext) <- ViewNewStyle.createCustomView(fromBankIdAccountId, targetCreateCustomViewJson.toCreateViewJson, callContext)
-//
-// _ <-ViewNewStyle.grantAccessToCustomView(vrpView, user, callContext)
-//
-// //3rd: Create a new counterparty on that view (_VRP-9d429899-24f5-42c8-8565-943ffa6a7945)
-// postJson = PostCounterpartyJson400(
-// name = postConsentRequestJsonV510.to_account.counterparty_name,
-// description = postConsentRequestJsonV510.to_account.counterparty_name,
-// currency = postConsentRequestJsonV510.to_account.limit.currency,
-// other_account_routing_scheme = StringHelpers.snakify(postConsentRequestJsonV510.to_account.account_routing.scheme).toUpperCase,
-// other_account_routing_address = postConsentRequestJsonV510.to_account.account_routing.address,
-// other_account_secondary_routing_scheme = "",
-// other_account_secondary_routing_address = "",
-// other_bank_routing_scheme = StringHelpers.snakify(postConsentRequestJsonV510.to_account.bank_routing.scheme).toUpperCase,
-// other_bank_routing_address = postConsentRequestJsonV510.to_account.bank_routing.address,
-// other_branch_routing_scheme = StringHelpers.snakify(postConsentRequestJsonV510.to_account.branch_routing.scheme).toUpperCase,
-// other_branch_routing_address = postConsentRequestJsonV510.to_account.branch_routing.address,
-// is_beneficiary = true,
-// bespoke = Nil
-// )
-// _ <- Helper.booleanToFuture(s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}", cc = callContext) {
-// postJson.description.length <= 36
-// }
-//
-//
-// (counterparty, callContext) <- Connector.connector.vend.checkCounterpartyExists(postJson.name, fromBankIdAccountId.bankId.value, fromBankIdAccountId.accountId.value, vrpView.viewId.value, callContext)
-//
-// _ <- Helper.booleanToFuture(CounterpartyAlreadyExists.replace("value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.",
-// s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${fromBankIdAccountId.bankId.value}) and ACCOUNT_ID(${fromBankIdAccountId.accountId.value}) and VIEW_ID($vrpViewId)"), cc = callContext) {
-// counterparty.isEmpty
-// }
-//
-// _ <- Helper.booleanToFuture(s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'", cc = callContext) {
-// isValidCurrencyISOCode(postJson.currency)
-// }
-//
-// (counterparty, callContext) <- NewStyle.function.createCounterparty(
-// name = postJson.name,
-// description = postJson.description,
-// currency = postJson.currency,
-// createdByUserId = user.userId,
-// thisBankId = fromBankIdAccountId.bankId.value,
-// thisAccountId = fromBankIdAccountId.accountId.value,
-// thisViewId = vrpViewId,
-// otherAccountRoutingScheme = postJson.other_account_routing_scheme,
-// otherAccountRoutingAddress = postJson.other_account_routing_address,
-// otherAccountSecondaryRoutingScheme = postJson.other_account_secondary_routing_scheme,
-// otherAccountSecondaryRoutingAddress = postJson.other_account_secondary_routing_address,
-// otherBankRoutingScheme = postJson.other_bank_routing_scheme,
-// otherBankRoutingAddress = postJson.other_bank_routing_address,
-// otherBranchRoutingScheme = postJson.other_branch_routing_scheme,
-// otherBranchRoutingAddress = postJson.other_branch_routing_address,
-// isBeneficiary = postJson.is_beneficiary,
-// bespoke = postJson.bespoke.map(bespoke => CounterpartyBespoke(bespoke.key, bespoke.value)),
-// callContext
-// )
-//
-// postCounterpartyLimitV510 = PostCounterpartyLimitV510(
-// currency = postConsentRequestJsonV510.to_account.limit.currency,
-// max_single_amount = postConsentRequestJsonV510.to_account.limit.max_single_amount,
-// max_monthly_amount = postConsentRequestJsonV510.to_account.limit.max_monthly_amount,
-// max_number_of_monthly_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_monthly_transactions,
-// max_yearly_amount = postConsentRequestJsonV510.to_account.limit.max_yearly_amount,
-// max_number_of_yearly_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_yearly_transactions,
-// max_total_amount = postConsentRequestJsonV510.to_account.limit.max_total_amount,
-// max_number_of_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_transactions
-// )
-//
-// //4th: create the counterparty limit
-// (counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit(
-// fromBankIdAccountId.bankId.value,
-// fromBankIdAccountId.accountId.value,
-// vrpViewId,
-// counterparty.counterpartyId,
-// cc.callContext
-// )
-// failMsg = s"$CounterpartyLimitAlreadyExists Current BANK_ID(${fromBankIdAccountId.bankId.value}), " +
-// s"ACCOUNT_ID(${fromBankIdAccountId.accountId.value}), VIEW_ID($vrpViewId),COUNTERPARTY_ID(${counterparty.counterpartyId})"
-// _ <- Helper.booleanToFuture(failMsg, cc = callContext) {
-// counterpartyLimitBox.isEmpty
-// }
-// (counterpartyLimit, callContext) <- NewStyle.function.createOrUpdateCounterpartyLimit(
-// bankId = counterparty.thisBankId,
-// accountId = counterparty.thisAccountId,
-// viewId = counterparty.thisViewId,
-// counterpartyId = counterparty.counterpartyId,
-// postCounterpartyLimitV510.currency,
-// BigDecimal(postCounterpartyLimitV510.max_single_amount),
-// BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
-// postCounterpartyLimitV510.max_number_of_monthly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
-// postCounterpartyLimitV510.max_number_of_yearly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_total_amount),
-// postCounterpartyLimitV510.max_number_of_transactions,
-// cc.callContext
-// )
-//
-// } yield {
-// (fromAccount.bankId, fromAccount.accountId, vrpView.viewId, CounterpartyId(counterparty.counterpartyId))
-// }
-// }else{
-// Future.successful(BankId(""), AccountId(""), ViewId(""),CounterpartyId(""))
-// }
-//
-// maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
-// _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){
-// consentRequestJson.time_to_live match {
-// case Some(ttl) => ttl <= maxTimeToLive
-// case _ => true
-// }
-// }
-// requestedEntitlements = consentRequestJson.entitlements.getOrElse(Nil)
-// myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId)
-// _ <- Helper.booleanToFuture(RolesForbiddenInConsent, cc=callContext){
-// requestedEntitlements.map(_.role_name)
-// .intersect(
-// List(
-// canCreateEntitlementAtOneBank.toString(),
-// canCreateEntitlementAtAnyBank.toString())
-// ).length == 0
-// }
-// _ <- Helper.booleanToFuture(RolesAllowedInConsent, cc=callContext){
-// requestedEntitlements.forall(
-// re => myEntitlements.getOrElse(Nil).exists(
-// e => e.roleName == re.role_name && e.bankId == re.bank_id
-// )
-// )
-// }
-// postConsentViewJsons <- if(isVrpConsent) {
-// Future.successful(List(PostConsentViewJsonV310(
-// bankId.value,
-// accountId.value,
-// viewId.value
-// )))
-// }else{
-// Future.sequence(
-// consentRequestJson.account_access.map(
-// access =>
-// NewStyle.function.getBankAccountByRouting(consentRequestJson.bank_id.map(BankId(_)),access.account_routing.scheme, access.account_routing.address, cc.callContext)
-// .map(result =>PostConsentViewJsonV310(
-// result._1.bankId.value,
-// result._1.accountId.value,
-// access.view_id
-// ))
-// )
-// )
-// }
-//
-// (_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
-// _ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc=callContext){
-// postConsentViewJsons.forall(
-// rv => assignedViews.exists{
-// e =>
-// e.view_id == rv.view_id &&
-// e.bank_id == rv.bank_id &&
-// e.account_id == rv.account_id
-// }
-// )
-// }
-// // Use consumer specified at the payload of consent request in preference to the field ConsumerId of consent request
-// // i.e. ConsentRequest.Payload.consumer_id in preference to ConsentRequest.ConsumerId
-// calculatedConsumerId = consentRequestJson.consumer_id.orElse(Some(createdConsentRequest.consumerId))
-// (consumerId, applicationText) <- calculatedConsumerId match {
-// case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map {
-// c => (Some(c.consumerId.get), c.description)
-// }
-// case None => Future(None, "Any application")
-// }
-//
-// challengeAnswer = Props.mode match {
-// case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
-// case _ => SecureRandomUtil.numeric()
-// }
-// consumer = Consumers.consumers.vend.getConsumerByConsumerId(calculatedConsumerId.getOrElse("None"))
-// createdConsent <- Future(
-// Consents.consentProvider.vend.createObpConsent(
-// user,
-// challengeAnswer,
-// Some(consentRequestId),
-// consumer
-// )
-// ) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-//
-// postConsentBodyCommonJson = PostConsentBodyCommonJson(
-// everything = consentRequestJson.everything,
-// bank_id = consentRequestJson.bank_id,
-// views = postConsentViewJsons,
-// entitlements = consentRequestJson.entitlements.getOrElse(Nil),
-// consumer_id = consentRequestJson.consumer_id,
-// consent_request_id = Some(consentRequestId),
-// valid_from = consentRequestJson.valid_from,
-// time_to_live = consentRequestJson.time_to_live,
-// )
-//
-// consentJWT = Consent.createConsentJWT(
-// user,
-// postConsentBodyCommonJson,
-// createdConsent.secret,
-// createdConsent.consentId,
-// consumerId,
-// postConsentBodyCommonJson.valid_from,
-// postConsentBodyCommonJson.time_to_live.getOrElse(3600),
-// Some(HelperInfoJson(List(counterpartyId.value)))
-// )
-// _ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// validUntil = Helper.calculateValidTo(postConsentBodyCommonJson.valid_from, postConsentBodyCommonJson.time_to_live.getOrElse(3600))
-// _ <- Future(Consents.consentProvider.vend.setValidUntil(createdConsent.consentId, validUntil)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// //we need to check `skip_consent_sca_for_consumer_id_pairs` props, to see if we really need the SCA flow.
-// //this is from callContext
-// grantorConsumerId = callContext.map(_.consumer.toOption.map(_.consumerId.get)).flatten.getOrElse("Unknown")
-// //this is from json body
-// granteeConsumerId = postConsentBodyCommonJson.consumer_id.getOrElse("Unknown")
-//
-// shouldSkipConsentScaForConsumerIdPair = APIUtil.skipConsentScaForConsumerIdPairs.contains(
-// APIUtil.ConsumerIdPair(
-// grantorConsumerId,
-// granteeConsumerId
-// ))
-// mappedConsent <- if (shouldSkipConsentScaForConsumerIdPair) {
-// Future{
-// MappedConsent.find(By(MappedConsent.mConsentId, createdConsent.consentId)).map(_.mStatus(ConsentStatus.ACCEPTED.toString).saveMe()).head
-// }
-// } else {
-// val challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText"
-// scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email
-// sendEmailNotification(callContext, consentRequestJson, challengeText)
-// case v if v == StrongCustomerAuthentication.SMS.toString =>
-// sendSmsNotification(callContext, consentRequestJson, challengeText)
-// case v if v == StrongCustomerAuthentication.IMPLICIT.toString =>
-// for {
-// (consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
-// status <- consentImplicitSCA.scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
-// sendEmailNotification(callContext, consentRequestJson.copy(email = Some(consentImplicitSCA.recipient)), challengeText)
-// case v if v == StrongCustomerAuthentication.SMS =>
-// sendSmsNotification(callContext, consentRequestJson.copy(phone_number = Some(consentImplicitSCA.recipient)), challengeText)
-// case _ => Future {
-// "Success"
-// }
-// }} yield {
-// status
-// }
-// case _ => Future {
-// "Success"
-// }
-// }
-// Future{createdConsent}
-// }
-// } yield {
-// (ConsentJsonV500(
-// mappedConsent.consentId,
-// consentJWT,
-// mappedConsent.status,
-// Some(mappedConsent.consentRequestId),
-// if (isVRPConsentRequest) Some(
-// ConsentAccountAccessJson(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// Some(HelperInfoJson(List(counterpartyId.value))))
-// )
-// else None
-// ), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// headAtms,
-// implementedInApiVersion,
-// nameOf(headAtms),
-// "HEAD",
-// "/banks/BANK_ID/atms",
-// "Head Bank ATMS",
-// s"""Head Bank ATMS.""",
-// EmptyBody,
-// atmsJsonV400,
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-// lazy val headAtms : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonHead _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getAtmsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// } yield {
-// ("", HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomer,
-// implementedInApiVersion,
-// nameOf(createCustomer),
-// "POST",
-// "/banks/BANK_ID/customers",
-// "Create Customer",
-// s"""
-// |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.
-// |Dates need to be in the format 2013-01-21T23:08:00Z
-// |
-// |If kyc_status is not provided, it defaults to false.
-// |
-// |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// postCustomerJsonV500,
-// customerJsonV310,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateConsumerError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson),
-// Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))
-// )
-// lazy val createCustomer : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV500 ", 400, cc.callContext) {
-// json.extract[PostCustomerJsonV500]
-// }
-// _ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants.getOrElse(0)}) not equal the length(${postedData.dob_of_dependants.getOrElse(Nil).length }) of dob_of_dependants array", 400, cc.callContext) {
-// postedData.dependants.getOrElse(0) == postedData.dob_of_dependants.getOrElse(Nil).length
-// }
-// customerNumber = postedData.customer_number.getOrElse(Random.nextInt(Integer.MAX_VALUE).toString)
-//
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat customer_number can not contain `::::` characters", cc=cc.callContext) {
-// !`checkIfContains::::` (customerNumber)
-// }
-// (_, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, customerNumber, cc.callContext)
-// (customer, callContext) <- NewStyle.function.createCustomerC2(
-// bankId,
-// postedData.legal_name,
-// customerNumber,
-// postedData.mobile_phone_number,
-// postedData.email.getOrElse(""),
-// CustomerFaceImage(
-// postedData.face_image.map(_.date).getOrElse(null),
-// postedData.face_image.map(_.url).getOrElse("")
-// ),
-// postedData.date_of_birth.getOrElse(null),
-// postedData.relationship_status.getOrElse(""),
-// postedData.dependants.getOrElse(0),
-// postedData.dob_of_dependants.getOrElse(Nil),
-// postedData.highest_education_attained.getOrElse(""),
-// postedData.employment_status.getOrElse(""),
-// postedData.kyc_status.getOrElse(false),
-// postedData.last_ok_date.getOrElse(null),
-// postedData.credit_rating.map(i => CreditRating(i.rating, i.source)),
-// postedData.credit_limit.map(i => CreditLimit(i.currency, i.amount)),
-// postedData.title.getOrElse(""),
-// postedData.branch_id.getOrElse(""),
-// postedData.name_suffix.getOrElse(""),
-// "",
-// "",
-// callContext,
-// )
-// } yield {
-// (JSONFactory310.createCustomerJson(customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerOverview,
-// implementedInApiVersion,
-// nameOf(getCustomerOverview),
-// "POST",
-// "/banks/BANK_ID/customers/customer-number-query/overview",
-// "Get Customer Overview",
-// s"""Gets the Customer Overview specified by customer_number and bank_code.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerOverviewJsonV500,
-// customerOverviewJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomerOverview))
-// )
-//
-// lazy val getCustomerOverview : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "customer-number-query" :: "overview" :: Nil JsonPost json -> req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerOverviewJsonV500 ", 400, cc.callContext) {
-// json.extract[PostCustomerOverviewJsonV500]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerNumber(postedData.customer_number, bankId, cc.callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customer.customerId),
-// callContext: Option[CallContext])
-// accountIds <- AccountAttributeX.accountAttributeProvider.vend
-// .getAccountIdsByParams(bankId, List("customer_number" -> List(postedData.customer_number)).toMap)
-// (accounts: List[BankAccount], callContext) <- NewStyle.function.getBankAccounts(accountIds.toList.flatten.map(i => BankIdAccountId(bankId, AccountId(i))), callContext)
-// (accountAttributes, callContext) <- NewStyle.function.getAccountAttributesForAccounts(
-// bankId,
-// accounts,
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory500.createCustomerWithAttributesJson(customer, customerAttributes, accountAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerOverviewFlat,
-// implementedInApiVersion,
-// nameOf(getCustomerOverviewFlat),
-// "POST",
-// "/banks/BANK_ID/customers/customer-number-query/overview-flat",
-// "Get Customer Overview Flat",
-// s"""Gets the Customer Overview Flat specified by customer_number and bank_code.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerOverviewJsonV500,
-// customerOverviewFlatJsonV500,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomerOverviewFlat))
-// )
-//
-// lazy val getCustomerOverviewFlat : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "customer-number-query" :: "overview-flat" :: Nil JsonPost json -> req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerOverviewJsonV500 ", 400, cc.callContext) {
-// json.extract[PostCustomerOverviewJsonV500]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerNumber(postedData.customer_number, bankId, cc.callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customer.customerId),
-// callContext: Option[CallContext])
-// accountIds <- AccountAttributeX.accountAttributeProvider.vend
-// .getAccountIdsByParams(bankId, List("customer_number" -> List(postedData.customer_number)).toMap)
-// (accounts: List[BankAccount], callContext) <- NewStyle.function.getBankAccounts(accountIds.toList.flatten.map(i => BankIdAccountId(bankId, AccountId(i))), callContext)
-// (accountAttributes, callContext) <- NewStyle.function.getAccountAttributesForAccounts(
-// bankId,
-// accounts,
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory500.createCustomerOverviewFlatJson(customer, customerAttributes, accountAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getMyCustomersAtAnyBank,
-// implementedInApiVersion,
-// nameOf(getMyCustomersAtAnyBank),
-// "GET",
-// "/my/customers",
-// "Get My Customers",
-// """Gets all Customers that are linked to me.
-// |
-// |Authentication via OAuth is required.""",
-// EmptyBody,
-// customerJsonV210,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser))
-//
-// lazy val getMyCustomersAtAnyBank : OBPEndpoint = {
-// case "my" :: "customers" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (customers, callContext) <- Connector.connector.vend.getCustomersByUserId(u.userId, callContext) map {
-// connectorEmptyResponse(_, callContext)
-// }
-// } yield {
-// (JSONFactory210.createCustomersJson(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyCustomersAtBank,
-// implementedInApiVersion,
-// nameOf(getMyCustomersAtBank),
-// "GET",
-// "/banks/BANK_ID/my/customers",
-// "Get My Customers at Bank",
-// s"""Returns a list of Customers at the Bank that are linked to the currently authenticated User.
-// |
-// |
-// |${userAuthenticationMessage(true)}""".stripMargin,
-// EmptyBody,
-// customerJSONs,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer)
-// )
-//
-// lazy val getMyCustomersAtBank : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "customers" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (customers, callContext) <- Connector.connector.vend.getCustomersByUserId(u.userId, callContext) map {
-// connectorEmptyResponse(_, callContext)
-// }
-// } yield {
-// // Filter so we only see the ones for the bank in question
-// val bankCustomers = customers.filter(_.bankId==bankId.value)
-// val json = JSONFactory210.createCustomersJson(bankCustomers)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersAtOneBank,
-// implementedInApiVersion,
-// nameOf(getCustomersAtOneBank),
-// "GET",
-// "/banks/BANK_ID/customers",
-// "Get Customers at Bank",
-// s"""Get Customers at Bank.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customersJsonV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersAtOneBank : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
-// customers <- NewStyle.function.getCustomers(bankId, callContext, requestParams)
-// } yield {
-// (JSONFactory300.createCustomersJson(customers.sortBy(_.bankId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersMinimalAtOneBank,
-// implementedInApiVersion,
-// nameOf(getCustomersMinimalAtOneBank),
-// "GET",
-// "/banks/BANK_ID/customers-minimal",
-// "Get Customers Minimal at Bank",
-// s"""Get Customers Minimal at Bank.
-// |
-// |
-// |
-// |""",
-// EmptyBody,
-// customersMinimalJsonV300,
-// List(
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersMinimalAtOneBank))
-// )
-// lazy val getCustomersMinimalAtOneBank : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers-minimal" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
-// customers <- NewStyle.function.getCustomers(bankId, callContext, requestParams)
-// } yield {
-// (createCustomersMinimalJson(customers.sortBy(_.bankId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createProduct,
-// implementedInApiVersion,
-// nameOf(createProduct),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE",
-// "Create Product",
-// s"""Create or Update Product for the Bank.
-// |
-// |The combination of bank_id and product_code is unique. If a Product already exists for the bank_id and product_code, it will be updated.
-// |
-// |Typical Super Family values / Asset classes are:
-// |
-// |Debt
-// |Equity
-// |FX
-// |Commodity
-// |Derivative
-// |
-// |$productHiearchyAndCollectionNote
-// |
-// |
-// |${userAuthenticationMessage(true) }
-// |
-// |
-// |""",
-// putProductJsonV500,
-// productJsonV400.copy(attributes = None, fees = None),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(List(canCreateProduct, canCreateProductAtAnyBank))
-// )
-// lazy val createProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PutProductJsonV500 "
-// product <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PutProductJsonV500]
-// }
-// (parentProduct, callContext) <- product.parent_product_code.trim.nonEmpty match {
-// case false =>
-// Future((Empty, callContext))
-// case true =>
-// NewStyle.function.getProduct(bankId, ProductCode(product.parent_product_code), callContext).map(product => (Full(product._1),product._2))
-// }
-// (success, callContext) <- NewStyle.function.createOrUpdateProduct(
-// bankId = bankId.value,
-// code = productCode.value,
-// parentProductCode = parentProduct.map(_.code.value).toOption,
-// name = product.name,
-// category = null,
-// family = null,
-// superFamily = null,
-// moreInfoUrl = product.more_info_url.getOrElse(""),
-// termsAndConditionsUrl = product.terms_and_conditions_url.getOrElse(""),
-// details = null,
-// description = product.description.getOrElse(""),
-// metaLicenceId = product.meta.map(_.license.id).getOrElse(""),
-// metaLicenceName = product.meta.map(_.license.name).getOrElse(""),
-// callContext
-// )
-// } yield {
-// (JSONFactory400.createProductJson(success), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// addCardForBank,
-// implementedInApiVersion,
-// nameOf(addCardForBank),
-// "POST",
-// "/management/banks/BANK_ID/cards",
-// "Create Card",
-// s"""Create Card at bank specified by BANK_ID .
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// createPhysicalCardJsonV500,
-// physicalCardJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// AllowedValuesAre,
-// UnknownError
-// ),
-// List(apiTagCard),
-// Some(List(canCreateCardsForBank)))
-// lazy val addCardForBank: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), _,callContext) <- SS.userBank
-//
-// failMsg = s"$InvalidJsonFormat The Json body should be the $CreatePhysicalCardJsonV500 "
-// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {json.extract[CreatePhysicalCardJsonV500]}
-//
-// _ <- postJson.allows match {
-// case List() => Future {true}
-// case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a)))
-// }
-//
-// failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ")
-// cardReplacementReason <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// postJson.replacement match {
-// case Some(value) => CardReplacementReason.valueOf(value.reason_requested)
-// case None => CardReplacementReason.valueOf(CardReplacementReason.FIRST.toString)
-// }
-// }
-//
-// _<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10)
-//
-// (_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext)
-//
-// (_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext)
-//
-// replacement = postJson.replacement match {
-// case Some(replacement) =>
-// Some(CardReplacementInfo(requestedDate = replacement.requested_date, cardReplacementReason))
-// case None => None
-// }
-// collected = postJson.collected match {
-// case Some(collected) => Some(CardCollectionInfo(collected))
-// case None => None
-// }
-// posted = postJson.posted match {
-// case Some(posted) => Option(CardPostedInfo(posted))
-// case None => None
-// }
-//
-// cvv = ThreadLocalRandom.current().nextLong(100, 999)
-//
-// (card, callContext) <- NewStyle.function.createPhysicalCard(
-// bankCardNumber=postJson.card_number,
-// nameOnCard=postJson.name_on_card,
-// cardType = postJson.card_type,
-// issueNumber=postJson.issue_number,
-// serialNumber=postJson.serial_number,
-// validFrom=postJson.valid_from_date,
-// expires=postJson.expires_date,
-// enabled=postJson.enabled,
-// cancelled=false,
-// onHotList=false,
-// technology=postJson.technology,
-// networks= postJson.networks,
-// allows= postJson.allows,
-// accountId= postJson.account_id,
-// bankId=bankId.value,
-// replacement = replacement,
-// pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))),
-// collected = collected,
-// posted = posted,
-// customerId = postJson.customer_id,
-// cvv = cvv.toString,
-// brand = postJson.brand,
-// callContext
-// )
-// } yield {
-// //NOTE: OBP do not store the 3 digits cvv, only the hash, so we copy it here.
-// (createPhysicalCardJson(card, u).copy(cvv=cvv.toString), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getViewsForBankAccount,
-// implementedInApiVersion,
-// nameOf(getViewsForBankAccount),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views",
-// "Get Views for Account",
-// s"""#Views
-// |
-// |
-// |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.
-// |
-// |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.
-// |
-// |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.
-// |
-// |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.
-// |
-// |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.
-// |
-// |**Metadata:**
-// |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.
-// |
-// |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).
-// |
-// |# All
-// |*Optional*
-// |
-// |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.
-// |
-// |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.""",
-// EmptyBody,
-// viewsJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount))
-//
-// lazy val getViewsForBankAccount : OBPEndpoint = {
-// //get the available views on an bank account
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val res =
-// for {
-// (Full(u), callContext) <- SS.user
-// permission <- NewStyle.function.permission(bankId, accountId, u, callContext)
-// anyViewContainsCanSeeAvailableViewsForBankAccountPermission = permission.views.map(_.allowed_actions.exists(_ == CAN_SEE_AVAILABLE_VIEWS_FOR_BANK_ACCOUNT)).find(_.==(true)).getOrElse(false)
-// _ <- Helper.booleanToFuture(
-// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_AVAILABLE_VIEWS_FOR_BANK_ACCOUNT)}` permission on any your views",
-// cc = callContext
-// ) {
-// anyViewContainsCanSeeAvailableViewsForBankAccountPermission
-// }
-// } yield {
-// for {
-// views <- Full(Views.views.vend.availableViewsForAccount(BankIdAccountId(bankId, accountId)))
-// } yield {
-// (createViewsJsonV500(views), HttpCode.`200`(cc.callContext))
-// }
-// }
-// res map { fullBoxOrException(_) } map { unboxFull(_) }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSystemView,
-// implementedInApiVersion,
-// "deleteSystemView",
-// "DELETE",
-// "/system-views/VIEW_ID",
-// "Delete System View",
-// "Deletes the system view specified by VIEW_ID",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// BankAccountNotFound,
-// UnknownError,
-// "user does not have owner access"
-// ),
-// List(apiTagSystemView),
-// Some(List(canDeleteSystemView))
-// )
-//
-// lazy val deleteSystemView: OBPEndpoint = {
-// case "system-views" :: viewId :: Nil JsonDelete req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- ViewNewStyle.systemView(ViewId(viewId), cc.callContext)
-// view <- ViewNewStyle.deleteSystemView(ViewId(viewId), cc.callContext)
-// } yield {
-// (Full(view), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMetricsAtBank,
-// implementedInApiVersion,
-// nameOf(getMetricsAtBank),
-// "GET",
-// "/management/metrics/banks/BANK_ID",
-// "Get Metrics at Bank",
-// s"""Get the all metrics at the Bank specified by BANK_ID
-// |
-// |require CanReadMetrics role
-// |
-// |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics
-// |
-// |Should be able to filter on the following metrics fields
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
-// |
-// |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString
-// |
-// |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString
-// |
-// |3 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |4 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |5 sort_by (defaults to date field) eg: sort_by=date
-// | possible values:
-// | "url",
-// | "date",
-// | "username" (or "user_name" for backward compatibility),
-// | "app_name",
-// | "developer_email",
-// | "implemented_by_partial_function",
-// | "implemented_in_version",
-// | "consumer_id",
-// | "verb"
-// |
-// |6 direction (defaults to date desc) eg: direction=desc
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78
-// |
-// |Other filters:
-// |
-// |7 consumer_id (if null ignore)
-// |
-// |8 user_id (if null ignore)
-// |
-// |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |10 url (if null ignore), note: can not contain '&'.
-// |
-// |11 app_name (if null ignore)
-// |
-// |12 implemented_by_partial_function (if null ignore),
-// |
-// |13 implemented_in_version (if null ignore)
-// |
-// |14 verb (if null ignore)
-// |
-// |15 correlation_id (if null ignore)
-// |
-// |16 duration (if null ignore) non digit chars will be silently omitted
-// |
-// """.stripMargin,
-// EmptyBody,
-// metricsJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canGetMetricsAtOneBank)))
-//
-// lazy val getMetricsAtBank : OBPEndpoint = {
-// case "management" :: "metrics" :: "banks" :: bankId :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, cc.callContext)
-// metrics <- Future(APIMetrics.apiMetrics.vend.getAllMetrics(obpQueryParams ::: List(OBPBankId(bankId))))
-// } yield {
-// (JSONFactory210.createMetricsJson(metrics), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemView,
-// implementedInApiVersion,
-// "getSystemView",
-// "GET",
-// "/system-views/VIEW_ID",
-// "Get System View",
-// s"""Get System View
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// viewJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canGetSystemView))
-// )
-//
-// lazy val getSystemView: OBPEndpoint = {
-// case "system-views" :: viewId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// view <- ViewNewStyle.systemView(ViewId(viewId), cc.callContext)
-// } yield {
-// (createViewJsonV500(view), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemViewsIds,
-// implementedInApiVersion,
-// nameOf(getSystemViewsIds),
-// "GET",
-// "/system-views-ids",
-// "Get Ids of System Views",
-// s"""Get Ids of System Views
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// viewIdsJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canGetSystemView))
-// )
-//
-// lazy val getSystemViewsIds: OBPEndpoint = {
-// case "system-views-ids" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// views <- ViewNewStyle.systemViews()
-// } yield {
-// (createViewsIdsJsonV500(views), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createSystemView,
-// implementedInApiVersion,
-// nameOf(createSystemView),
-// "POST",
-// "/system-views",
-// "Create System View",
-// s"""Create a system view
-// |
-// | ${userAuthenticationMessage(true)} and the user needs to have access to the $canCreateSystemView entitlement.
-// |
-// | The 'allowed_actions' field is a list containing the names of the actions allowed through this view.
-// | All the actions contained in the list will be set to `true` on the view creation, the rest will be set to `false`.
-// |
-// | The 'alias' field in the JSON can take one of three values:
-// |
-// | * _public_: to use the public alias if there is one specified for the other account.
-// | * _private_: to use the private alias if there is one specified for the other account.
-// | * _''(empty string)_: to use no alias; the view shows the real name of the other account.
-// |
-// | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.
-// |
-// | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.
-// |
-// | System views cannot be public. In case you try to set it you will get the error $SystemViewCannotBePublicError
-// | """,
-// createSystemViewJsonV500,
-// viewJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canCreateSystemView))
-// )
-//
-// lazy val createSystemView : OBPEndpoint = {
-// //creates a system view
-// case "system-views" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// createViewJson <- NewStyle.function.tryons(failMsg = s"$InvalidJsonFormat The Json body should be the $CreateViewJson ", 400, cc.callContext) {
-// json.extract[CreateViewJsonV500]
-// }
-// _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=cc.callContext) {
-// createViewJson.is_public == false
-// }
-// // custom views are started with `_`,eg _ life, _ work, and System views can not, eg: owner.
-// _ <- Helper.booleanToFuture(failMsg = InvalidSystemViewFormat +s"Current view_name (${createViewJson.name})", cc = cc.callContext) {
-// isValidSystemViewName(createViewJson.name)
-// }
-// view <- ViewNewStyle.createSystemView(createViewJson.toCreateViewJson, cc.callContext)
-// } yield {
-// (createViewJsonV500(view), HttpCode.`201`(cc.callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateSystemView,
-// implementedInApiVersion,
-// nameOf(updateSystemView),
-// "PUT",
-// "/system-views/VIEW_ID",
-// "Update System View",
-// s"""Update an existing view on a bank account
-// |
-// |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.
-// |
-// |The json sent is the same as during view creation (above), with one difference: the 'name' field
-// |of a view is not editable (it is only set when a view is created)""",
-// updateSystemViewJson500,
-// viewJsonV500,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canUpdateSystemView))
-// )
-//
-// lazy val updateSystemView : OBPEndpoint = {
-// //updates a view on a bank account
-// case "system-views" :: viewId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// updateJson <- Future { tryo{json.extract[UpdateViewJsonV500]} } map {
-// val msg = s"$InvalidJsonFormat The Json body should be the $UpdateViewJSON "
-// x => unboxFullOrFail(x, cc.callContext, msg)
-// }
-// _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=cc.callContext) {
-// updateJson.is_public == false
-// }
-// _ <- ViewNewStyle.systemView(ViewId(viewId), cc.callContext)
-// updatedView <- ViewNewStyle.updateSystemView(ViewId(viewId), updateJson.toUpdateViewJson, cc.callContext)
-// } yield {
-// (createViewJsonV500(updatedView), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomerAccountLink,
-// implementedInApiVersion,
-// nameOf(createCustomerAccountLink),
-// "POST",
-// "/banks/BANK_ID/customer-account-links",
-// "Create Customer Account Link",
-// s"""Link a Customer to a Account
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// createCustomerAccountLinkJson,
-// customerAccountLinkJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// BankAccountNotFound,
-// InvalidJsonFormat,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// AccountAlreadyExistsForCustomer,
-// CreateCustomerAccountLinkError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagAccount),
-// Some(List(canCreateCustomerAccountLink)))
-// lazy val createCustomerAccountLink : OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "customer-account-links" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _,callContext) <- SS.userBank
-//
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CreateCustomerAccountLinkJson ", 400, callContext) {
-// json.extract[CreateCustomerAccountLinkJson]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(postedData.customer_id, callContext)
-// _ <- booleanToFuture(s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to matches BANK_ID(${bankId.value}) in URL", 400, callContext) {
-// customer.bankId == bankId.value
-// }
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, AccountId(postedData.account_id), callContext)
-// _ <- booleanToFuture("Field customer_id is not defined in the posted json!", 400, callContext) {
-// postedData.customer_id.nonEmpty
-// }
-// (customerAccountLinkExists, callContext) <- Connector.connector.vend.getCustomerAccountLink(postedData.customer_id, postedData.account_id, callContext)
-// _ <- booleanToFuture(AccountAlreadyExistsForCustomer, 400, callContext) {
-// customerAccountLinkExists.isEmpty
-// }
-// (customerAccountLink, callContext) <- NewStyle.function.createCustomerAccountLink(postedData.customer_id, postedData.bank_id, postedData.account_id, postedData.relationship_type, callContext)
-// } yield {
-// (JSONFactory500.createCustomerAccountLinkJson(customerAccountLink), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAccountLinksByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCustomerAccountLinksByCustomerId),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/customer-account-links",
-// "Get Customer Account Links by CUSTOMER_ID",
-// s""" Get Customer Account Links by CUSTOMER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAccountLinksJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerAccountLinks)))
-// lazy val getCustomerAccountLinksByCustomerId : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "customer-account-links" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, cc.callContext)
-// _ <- booleanToFuture(s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to matches BANK_ID(${bankId.value}) in URL", 400, callContext) {
-// customer.bankId == bankId.value
-// }
-// (customerAccountLinks, callContext) <- NewStyle.function.getCustomerAccountLinksByCustomerId(customerId, callContext)
-// } yield {
-// (JSONFactory500.createCustomerAccountLinksJon(customerAccountLinks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAccountLinksByBankIdAccountId,
-// implementedInApiVersion,
-// nameOf(getCustomerAccountLinksByBankIdAccountId),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/customer-account-links",
-// "Get Customer Account Links by ACCOUNT_ID",
-// s""" Get Customer Account Links by ACCOUNT_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAccountLinksJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// BankAccountNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerAccountLinks)))
-// lazy val getCustomerAccountLinksByBankIdAccountId : OBPEndpoint = {
-// case "banks" :: bankId :: "accounts" :: accountId :: "customer-account-links" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _,callContext) <- SS.userBank
-// (customerAccountLinks, callContext) <- NewStyle.function.getCustomerAccountLinksByBankIdAccountId(bankId, accountId, callContext)
-// } yield {
-// (JSONFactory500.createCustomerAccountLinksJon(customerAccountLinks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerAccountLinkById,
-// implementedInApiVersion,
-// nameOf(getCustomerAccountLinkById),
-// "GET",
-// "/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID",
-// "Get Customer Account Link by Id",
-// s""" Get Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerAccountLinkJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerAccountLink)))
-// lazy val getCustomerAccountLinkById : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-account-links" :: customerAccountLinkId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _,callContext) <- SS.userBank
-// (customerAccountLink, callContext) <- NewStyle.function.getCustomerAccountLinkById(customerAccountLinkId, callContext)
-// } yield {
-// (JSONFactory500.createCustomerAccountLinkJson(customerAccountLink), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateCustomerAccountLinkById,
-// implementedInApiVersion,
-// nameOf(updateCustomerAccountLinkById),
-// "PUT",
-// "/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID",
-// "Update Customer Account Link by Id",
-// s""" Update Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// updateCustomerAccountLinkJson,
-// customerAccountLinkJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canUpdateCustomerAccountLink)))
-// lazy val updateCustomerAccountLinkById : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-account-links" :: customerAccountLinkId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), _,callContext) <- SS.userBank
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $UpdateCustomerAccountLinkJson ", 400, callContext) {
-// json.extract[UpdateCustomerAccountLinkJson]
-// }
-// (_, callContext) <- NewStyle.function.getCustomerAccountLinkById(customerAccountLinkId, callContext)
-//
-// (customerAccountLink, callContext) <- NewStyle.function.updateCustomerAccountLinkById(customerAccountLinkId, postedData.relationship_type, callContext)
-// } yield {
-// (JSONFactory500.createCustomerAccountLinkJson(customerAccountLink), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomerAccountLinkById,
-// implementedInApiVersion,
-// nameOf(deleteCustomerAccountLinkById),
-// "DELETE",
-// "/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID",
-// "Delete Customer Account Link",
-// s""" Delete Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canDeleteCustomerAccountLink)))
-// lazy val deleteCustomerAccountLinkById : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-account-links" :: customerAccountLinkId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), _,callContext) <- SS.userBank
-// (_, callContext) <- NewStyle.function.getCustomerAccountLinkById(customerAccountLinkId, callContext)
-// (deleted, callContext) <- NewStyle.function.deleteCustomerAccountLinkById(customerAccountLinkId, callContext)
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getAdapterInfo,
-// implementedInApiVersion,
-// nameOf(getAdapterInfo),
-// "GET",
-// "/adapter",
-// "Get Adapter Info",
-// s"""Get basic information about the Adapter.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// adapterInfoJsonV500,
-// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError),
-// List(apiTagApi),
-// Some(List(canGetAdapterInfo))
-// )
-// lazy val getAdapterInfo: OBPEndpoint = {
-// case "adapter" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- SS.user
-// (adapterInfo,_) <- NewStyle.function.getAdapterInfo(callContext)
-// } yield {
-// (JSONFactory500.createAdapterInfoJson(adapterInfo,cc.startTime.getOrElse(Helpers.now).getTime), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//}
-//
-//object APIMethods500 {
-// lazy val newStyleEndpoints: List[(String, String)] = Implementations5_0_0.resourceDocs.map {
-// rd => (rd.partialFunctionName, rd.implementedInApiVersion.toString())
-// }.toList
-//}
-//
diff --git a/obp-api/src/main/scala/code/api/v5_0_0/Http4s500.scala b/obp-api/src/main/scala/code/api/v5_0_0/Http4s500.scala
index b5fd379833..ef5c7f0f20 100644
--- a/obp-api/src/main/scala/code/api/v5_0_0/Http4s500.scala
+++ b/obp-api/src/main/scala/code/api/v5_0_0/Http4s500.scala
@@ -107,7 +107,7 @@ object Http4s500 {
val root: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `prefixPath` / "root" =>
val responseJson = convertAnyToJsonString(
- JSONFactory400.getApiInfoJSON(OBPAPI5_0_0.version, OBPAPI5_0_0.versionStatus)
+ JSONFactory400.getApiInfoJSON(ApiVersion.v5_0_0, versionStatus)
)
Ok(responseJson)
}
diff --git a/obp-api/src/main/scala/code/api/v5_0_0/OBPAPI5_0_0.scala b/obp-api/src/main/scala/code/api/v5_0_0/OBPAPI5_0_0.scala
deleted file mode 100644
index e9ed415726..0000000000
--- a/obp-api/src/main/scala/code/api/v5_0_0/OBPAPI5_0_0.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
-Open Bank Project - API
-Copyright (C) 2011-2019, TESOBE GmbH.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
-Email: contact@tesobe.com
-TESOBE GmbH.
-Osloer Strasse 16/17
-Berlin 13359, Germany
-
-This product includes software developed at
-TESOBE (http://www.tesobe.com/)
-
- */
-package code.api.v5_0_0
-
-import scala.language.reflectiveCalls
-import code.api.OBPRestHelper
-import code.api.util.VersionedOBPApis
-import code.api.v4_0_0.OBPAPI4_0_0
-import code.util.Helper.MdcLoggable
-import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
-
-/*
-This file defines which endpoints from all the versions are available in v5.0.0.
-All v5.0.0 endpoints have been migrated to Http4s500 — this object is retained
-only for resource-doc aggregation and the Lift dispatch registry.
- */
-object OBPAPI5_0_0 extends OBPRestHelper with MdcLoggable with VersionedOBPApis {
-
- val version: ApiVersion = ApiVersion.v5_0_0
- val versionStatus = ApiVersionStatus.STABLE.toString
-
- // Re-export so tests that import OBPAPI5_0_0.Implementations5_0_0 still compile
- // after APIMethods500 is replaced with an empty stub.
- val Implementations5_0_0 = Http4s500.Implementations5_0_0
-
- // All v5.0.0 endpoints live in Http4s500 — aggregate Http4s500.resourceDocs on top of v4.0.0.
- def allResourceDocs = collectResourceDocs(
- OBPAPI4_0_0.allResourceDocs,
- Http4s500.resourceDocs
- )
-
- // No Lift routes — all v5.0.0 endpoints are served by Http4s500.
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
- // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here.
-}
diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala
deleted file mode 100644
index 8474ddad33..0000000000
--- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala
+++ /dev/null
@@ -1,6025 +0,0 @@
-package code.api.v5_1_0
-
-/**
- * All v5.1.0 Lift endpoints have been migrated to Http4s510.
- * This stub is kept so that existing test files that import
- * APIMethods510.Implementations5_1_0 continue to compile.
- */
-object APIMethods510 {
- val Implementations5_1_0 = Http4s510.Implementations5_1_0
-}
-
-trait APIMethods510
-
-// ─── Original Lift implementation (commented out) ────────────────────────────
-//package code.api.v5_1_0
-//
-//
-//import scala.language.reflectiveCalls
-//import code.api.Constant
-//import code.api.Constant._
-//import code.api.OAuth2Login.{Keycloak, OBPOIDC}
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
-//import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{ConsentAccessAccountsJson, ConsentAccessJson}
-//import code.api.cache.RedisLogger
-//import code.api.util.APIUtil._
-//import code.api.util.ApiRole._
-//import code.api.util.ApiTag._
-//import code.api.util.ErrorMessages.{$AuthenticatedUserIsRequired, BankNotFound, ConsentNotFound, InvalidJsonFormat, UnknownError, UserNotFoundByUserId, AuthenticatedUserIsRequired, _}
-//import code.api.util.FutureUtil.{EndpointContext, EndpointTimeout}
-//import code.api.util.JwtUtil.{getSignedPayloadAsJson, verifyJwt}
-//import code.api.util.NewStyle.HttpCode
-//import code.api.util.NewStyle.function.extractQueryParams
-//import code.api.util.X509.{getCommonName, getEmailAddress, getOrganization}
-//import code.api.util._
-//import code.api.util.newstyle.Consumer.createConsumerNewStyle
-//import code.api.util.newstyle.RegulatedEntityNewStyle.{createRegulatedEntityNewStyle, deleteRegulatedEntityNewStyle, getRegulatedEntitiesNewStyle, getRegulatedEntityByEntityIdNewStyle}
-//import code.api.util.newstyle.{BalanceNewStyle, RegulatedEntityAttributeNewStyle, ViewNewStyle}
-//import code.api.v2_0_0.AccountsHelper.{accountTypeFilterText, getFilteredCoreAccounts}
-//import code.api.v2_1_0.{ConsumerRedirectUrlJSON, JSONFactory210}
-//import code.api.v3_0_0.JSONFactory300
-//import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
-//import code.api.v3_1_0.JSONFactory310.{createBadLoginStatusJson, createConsumerJSON}
-//import code.api.v3_1_0._
-//import code.api.v4_0_0.JSONFactory400.{createAccountBalancesJson, createBalancesJson, createNewCoreBankAccountJson}
-//import code.api.v4_0_0._
-//import code.api.v5_0_0.JSONFactory500
-//import code.api.v5_1_0.JSONFactory510.{createCallLimitJson, createConsentsInfoJsonV510, createConsentsJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson}
-//import code.atmattribute.AtmAttribute
-//import code.bankconnectors.Connector
-//import code.consent.{ConsentRequests, ConsentStatus, Consents, DoobieConsentQueries, MappedConsent}
-//import code.consumer.Consumers
-//import code.entitlement.Entitlement
-//import code.loginattempts.LoginAttempt
-//import code.metrics.APIMetrics
-//import code.model.dataAccess.{AuthUser, MappedBankAccount}
-//import code.model.{AppType, Consumer}
-//import code.ratelimiting.{RateLimiting, RateLimitingDI}
-//import code.regulatedentities.MappedRegulatedEntityProvider
-//import code.userlocks.UserLocksProvider
-//import code.users.Users
-//import code.util.Helper
-//import code.util.Helper.ObpS
-//import code.views.Views
-//import code.views.system.{AccountAccess, ViewDefinition, ViewPermission}
-//import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons}
-//import com.github.dwickern.macros.NameOf.nameOf
-//import com.openbankproject.commons.ExecutionContext.Implicits.global
-//import com.openbankproject.commons.model._
-//import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
-//import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
-//import net.liftweb.common.{Box, Empty, Full}
-//import com.openbankproject.commons.util.json
-//import org.json4s.{Extraction, compactRender, parse, prettyRender}
-//import net.liftweb.mapper.By
-//import net.liftweb.util.Helpers.tryo
-//import net.liftweb.util.{Helpers, Props, StringHelpers}
-//
-//import java.net.URLDecoder
-//import java.nio.charset.StandardCharsets
-//import java.time.{LocalDate, ZoneId}
-//import java.util.Date
-//import scala.collection.immutable.{List, Nil}
-//import scala.collection.mutable.ArrayBuffer
-//import scala.concurrent.Future
-//
-//trait APIMethods510 {
-// self: RestHelper =>
-//
-// val Implementations5_1_0 = new Implementations510()
-//
-// class Implementations510 extends Helper.MdcLoggable {
-//
-// val implementedInApiVersion: ScannedApiVersion = ApiVersion.v5_1_0
-//
-// private val staticResourceDocs = ArrayBuffer[ResourceDoc]()
-// def resourceDocs = staticResourceDocs
-//
-// val apiRelations = ArrayBuffer[ApiRelation]()
-// val codeContext = CodeContext(staticResourceDocs, apiRelations)
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// root,
-// implementedInApiVersion,
-// nameOf(root),
-// "GET",
-// "/root",
-// "Get API Info (root)",
-// """Returns information about:
-// |
-// |* API version
-// |* Hosted by information
-// |* Hosted at information
-// |* Energy source information
-// |* Git Commit""",
-// EmptyBody,
-// apiInfoJson400,
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil)
-//
-// lazy val root: OBPEndpoint = {
-// case (Nil | "root" :: Nil) JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (JSONFactory510.getApiInfoJSON(OBPAPI5_1_0.version,OBPAPI5_1_0.versionStatus), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// suggestedSessionTimeout,
-// implementedInApiVersion,
-// nameOf(suggestedSessionTimeout),
-// "GET",
-// "/ui/suggested-session-timeout",
-// "Get Suggested Session Timeout",
-// """Returns information about:
-// |
-// |* Suggested session timeout in case of a user inactivity
-// """,
-// EmptyBody,
-// SuggestedSessionTimeoutV510("300"),
-// List(UnknownError),
-// apiTagApi :: Nil)
-//
-// lazy val suggestedSessionTimeout: OBPEndpoint = {
-// case "ui" :: "suggested-session-timeout" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// timeoutInSeconds: Int <- Future(APIUtil.getPropsAsIntValue("session_inactivity_timeout_in_seconds", 300))
-// } yield {
-// (SuggestedSessionTimeoutV510(timeoutInSeconds.toString), HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getOAuth2ServerWellKnown,
-// implementedInApiVersion,
-// "getOAuth2ServerWellKnown",
-// "GET",
-// "/well-known",
-// "Get Well Known URIs",
-// """Get the OAuth2 server's public Well Known URIs.
-// |
-// """.stripMargin,
-// EmptyBody,
-// oAuth2ServerJwksUrisJson,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi))
-//
-// lazy val getOAuth2ServerWellKnown: OBPEndpoint = {
-// case "well-known" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// } yield {
-// // Read and normalize property
-// val providerPropBox = APIUtil.getPropsValue("oauth2.oidc_provider")
-//
-// // Define available providers
-// val availableProviders = Map(
-// "obp-oidc" -> WellKnownUriJsonV510("obp-oidc", OBPOIDC.wellKnownOpenidConfiguration.toURL.toString),
-// "keycloak" -> WellKnownUriJsonV510("keycloak", Keycloak.wellKnownOpenidConfiguration.toURL.toString)
-// )
-//
-// // Resolve list of providers to show
-// val providersToShow: List[WellKnownUriJsonV510] = providerPropBox match {
-// case Empty =>
-// // Property missing: show nothing
-// Nil
-//
-// case Full(value) if value.trim.isEmpty =>
-// // Empty string: show all
-// availableProviders.values.toList
-//
-// case Full(value) =>
-// val wanted = value
-// .split(",")
-// .map(_.trim.toLowerCase)
-// .filter(_.nonEmpty)
-// .toSet
-//
-// // Special case: "none" means show nothing
-// if (wanted.contains("none")) {
-// Nil
-// } else {
-// val (known, unknown) = wanted.partition(availableProviders.contains)
-// availableProviders
-// .filterKeys(known.contains)
-// .values
-// .toList
-// }
-//
-// case _ =>
-// // Unexpected case, fallback to show nothing
-// Nil
-// }
-//
-// (WellKnownUrisJsonV510(providersToShow), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// regulatedEntities,
-// implementedInApiVersion,
-// nameOf(regulatedEntities),
-// "GET",
-// "/regulated-entities",
-// "Get Regulated Entities",
-// """Returns information about:
-// |
-// |* Regulated Entities
-// """,
-// EmptyBody,
-// regulatedEntitiesJsonV510,
-// List(UnknownError),
-// apiTagDirectory :: apiTagApi :: Nil)
-//
-// lazy val regulatedEntities: OBPEndpoint = {
-// case "regulated-entities" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (entities, callContext) <- getRegulatedEntitiesNewStyle(cc.callContext)
-// } yield {
-// (createRegulatedEntitiesJson(entities), HttpCode.`200`(callContext))
-// }
-// }
-//
-// // Helper function to avoid code duplication
-// private def getLogCacheHelper(level: RedisLogger.LogLevel.Value, cc: CallContext): Future[(RedisLogger.LogTail, Option[CallContext])] = {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, cc.callContext)
-// limit = obpQueryParams.collectFirst { case OBPLimit(value) => value }
-// offset = obpQueryParams.collectFirst { case OBPOffset(value) => value }
-// logs <- Future(RedisLogger.getLogTail(level, limit, offset))
-// } yield {
-// (logs, HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheTraceEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheTraceEndpoint),
-// "GET",
-// "/system/log-cache/trace",
-// "Get Trace Level Log Cache",
-// """Returns TRACE level logs from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/trace?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheTrace, canGetSystemLogCacheAll)))
-//
-// lazy val logCacheTraceEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "trace" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheTrace, canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.TRACE, cc)
-// } yield result
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheDebugEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheDebugEndpoint),
-// "GET",
-// "/system/log-cache/debug",
-// "Get Debug Level Log Cache",
-// """Returns DEBUG level logs from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/debug?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheDebug, canGetSystemLogCacheAll)))
-//
-// lazy val logCacheDebugEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "debug" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheDebug, canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.DEBUG, cc)
-// } yield result
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheInfoEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheInfoEndpoint),
-// "GET",
-// "/system/log-cache/info",
-// "Get Info Level Log Cache",
-// """Returns INFO level logs from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/info?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheInfo, canGetSystemLogCacheAll)))
-//
-// lazy val logCacheInfoEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "info" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheInfo, canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.INFO, cc)
-// } yield result
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheWarningEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheWarningEndpoint),
-// "GET",
-// "/system/log-cache/warning",
-// "Get Warning Level Log Cache",
-// """Returns WARNING level logs from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/warning?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheWarning, canGetSystemLogCacheAll)))
-//
-// lazy val logCacheWarningEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "warning" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheWarning, canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.WARNING, cc)
-// } yield result
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheErrorEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheErrorEndpoint),
-// "GET",
-// "/system/log-cache/error",
-// "Get Error Level Log Cache",
-// """Returns ERROR level logs from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/error?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheError, canGetSystemLogCacheAll)))
-//
-// lazy val logCacheErrorEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "error" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheError, canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.ERROR, cc)
-// } yield result
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// logCacheAllEndpoint,
-// implementedInApiVersion,
-// nameOf(logCacheAllEndpoint),
-// "GET",
-// "/system/log-cache/all",
-// "Get All Level Log Cache",
-// """Returns logs of all levels from the system log cache.
-// |
-// |This endpoint supports pagination via the following optional query parameters:
-// |* limit - Maximum number of log entries to return
-// |* offset - Number of log entries to skip (for pagination)
-// |
-// |Example: GET /system/log-cache/all?limit=50&offset=100
-// """,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil,
-// Some(List(canGetSystemLogCacheAll)))
-//
-// lazy val logCacheAllEndpoint: OBPEndpoint = {
-// case "system" :: "log-cache" :: "all" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", cc.userId, List(canGetSystemLogCacheAll), cc.callContext)
-// result <- getLogCacheHelper(RedisLogger.LogLevel.ALL, cc)
-// } yield result
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getRegulatedEntityById,
-// implementedInApiVersion,
-// nameOf(getRegulatedEntityById),
-// "GET",
-// "/regulated-entities/REGULATED_ENTITY_ID",
-// "Get Regulated Entity",
-// """Get Regulated Entity By REGULATED_ENTITY_ID
-// """,
-// EmptyBody,
-// regulatedEntityJsonV510,
-// List(UnknownError),
-// apiTagDirectory :: apiTagApi :: Nil)
-//
-// lazy val getRegulatedEntityById: OBPEndpoint = {
-// case "regulated-entities" :: regulatedEntityId :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(regulatedEntityId, cc.callContext)
-// } yield {
-// (createRegulatedEntityJson(entity), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createRegulatedEntity,
-// implementedInApiVersion,
-// nameOf(createRegulatedEntity),
-// "POST",
-// "/regulated-entities",
-// "Create Regulated Entity",
-// s"""Create Regulated Entity
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// regulatedEntityPostJsonV510,
-// regulatedEntityJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canCreateRegulatedEntity))
-// )
-//
-// lazy val createRegulatedEntity: OBPEndpoint = {
-// case "regulated-entities" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $RegulatedEntityPostJsonV510 "
-// for {
-// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[RegulatedEntityPostJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `services` field is not valid JSON"
-// servicesString <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// prettyRender(postedData.services)
-// }
-// (entity, callContext) <- createRegulatedEntityNewStyle(
-// certificateAuthorityCaOwnerId = Some(postedData.certificate_authority_ca_owner_id),
-// entityCertificatePublicKey = Some(postedData.entity_certificate_public_key),
-// entityName = Some(postedData.entity_name),
-// entityCode = Some(postedData.entity_code),
-// entityType = Some(postedData.entity_type),
-// entityAddress = Some(postedData.entity_address),
-// entityTownCity = Some(postedData.entity_town_city),
-// entityPostCode = Some(postedData.entity_post_code),
-// entityCountry = Some(postedData.entity_country),
-// entityWebSite = Some(postedData.entity_web_site),
-// services = Some(servicesString),
-// cc.callContext
-// )
-// } yield {
-// (createRegulatedEntityJson(entity), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteRegulatedEntity,
-// implementedInApiVersion,
-// nameOf(deleteRegulatedEntity),
-// "DELETE",
-// "/regulated-entities/REGULATED_ENTITY_ID",
-// "Delete Regulated Entity",
-// s"""Delete Regulated Entity specified by REGULATED_ENTITY_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canDeleteRegulatedEntity)))
-//
-// lazy val deleteRegulatedEntity: OBPEndpoint = {
-// case "regulated-entities" :: regulatedEntityId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- deleteRegulatedEntityNewStyle(
-// regulatedEntityId: String,
-// cc.callContext: Option[CallContext]
-// )
-// } yield {
-// org.scalameta.logger.elem(deleted)
-// (Full(deleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// waitingForGodot,
-// implementedInApiVersion,
-// nameOf(waitingForGodot),
-// "GET",
-// "/waiting-for-godot",
-// "Waiting For Godot",
-// """Waiting For Godot
-// |
-// |Uses query parameter "sleep" in milliseconds.
-// |For instance: .../waiting-for-godot?sleep=50 means postpone response in 50 milliseconds.
-// |""".stripMargin,
-// EmptyBody,
-// WaitingForGodotJsonV510(sleep_in_milliseconds = 50),
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil)
-//
-// lazy val waitingForGodot: OBPEndpoint = {
-// case "waiting-for-godot" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// implicit val timeout = EndpointTimeout(Constant.mediumEndpointTimeoutInMillis) // Set endpoint timeout explicitly
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// sleep: String = httpParams.filter(_.name == "sleep").headOption
-// .map(_.values.headOption.getOrElse("0")).getOrElse("0")
-// sleepInMillis: Long = tryo(sleep.trim.toLong).getOrElse(0)
-// _ <- Future(Thread.sleep(sleepInMillis))
-// } yield {
-// (JSONFactory510.waitingForGodot(sleepInMillis), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllApiCollections,
-// implementedInApiVersion,
-// nameOf(getAllApiCollections),
-// "GET",
-// "/management/api-collections",
-// "Get All API Collections",
-// s"""Get All API Collections.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// apiCollectionsJson400,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApiCollection),
-// Some(canGetAllApiCollections :: Nil)
-// )
-//
-// lazy val getAllApiCollections: OBPEndpoint = {
-// case "management" :: "api-collections" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (apiCollections, callContext) <- NewStyle.function.getAllApiCollections(cc.callContext)
-// } yield {
-// (JSONFactory400.createApiCollectionsJsonV400(apiCollections), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createAgent,
-// implementedInApiVersion,
-// nameOf(createAgent),
-// "POST",
-// "/banks/BANK_ID/agents",
-// "Create Agent",
-// s"""
-// |${userAuthenticationMessage(true)}
-// |""",
-// postAgentJsonV510,
-// agentJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// AgentNumberAlreadyExists,
-// CreateAgentError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson)
-// )
-//
-// lazy val createAgent : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "agents" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// putData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostAgentJsonV510 ", 400, cc.callContext) {
-// json.extract[PostAgentJsonV510]
-// }
-// (agentNumberIsAvailable, callContext) <- NewStyle.function.checkAgentNumberAvailable(bankId, putData.agent_number, cc.callContext)
-// _ <- Helper.booleanToFuture(failMsg= s"$AgentNumberAlreadyExists Current agent_number(${putData.agent_number}) and Current bank_id(${bankId.value})", cc=callContext) {agentNumberIsAvailable}
-// (agent, callContext) <- NewStyle.function.createAgent(
-// bankId = bankId.value,
-// legalName = putData.legal_name,
-// mobileNumber = putData.mobile_phone_number,
-// agentNumber = putData.agent_number,
-// callContext,
-// )
-// (bankAccount, callContext) <- NewStyle.function.createBankAccount(
-// bankId,
-// AccountId(APIUtil.generateUUID()),
-// "AGENT",
-// "AGENT",
-// putData.currency,
-// 0,
-// putData.legal_name,
-// null,
-// Nil,
-// callContext
-// )
-// (_, callContext) <- NewStyle.function.createAgentAccountLink(agent.agentId, bankAccount.bankId.value, bankAccount.accountId.value, callContext)
-//
-// } yield {
-// (JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAgentStatus,
-// implementedInApiVersion,
-// nameOf(updateAgentStatus),
-// "PUT",
-// "/banks/BANK_ID/agents/AGENT_ID",
-// "Update Agent status",
-// s"""
-// |${userAuthenticationMessage(true)}
-// |""",
-// putAgentJsonV510,
-// agentJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// AgentNotFound,
-// AgentAccountLinkNotFound,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson),
-// Some(canUpdateAgentStatusAtAnyBank :: canUpdateAgentStatusAtOneBank :: Nil)
-// )
-//
-// lazy val updateAgentStatus : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "agents" :: agentId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostAgentJsonV510 ", 400, cc.callContext) {
-// json.extract[PutAgentJsonV510]
-// }
-// (agent, callContext) <- NewStyle.function.getAgentByAgentId(agentId, cc.callContext)
-// (agentAccountLinks, callContext) <- NewStyle.function.getAgentAccountLinksByAgentId(agentId, callContext)
-// agentAccountLink <- NewStyle.function.tryons(AgentAccountLinkNotFound, 400, callContext) {
-// agentAccountLinks.head
-// }
-// (bankAccount, callContext) <- NewStyle.function.getBankAccount(BankId(agentAccountLink.bankId), AccountId(agentAccountLink.accountId), callContext)
-// (agent, callContext) <- NewStyle.function.updateAgentStatus(
-// agentId,
-// postedData.is_pending_agent,
-// postedData.is_confirmed_agent,
-// callContext)
-// } yield {
-// (JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAgent,
-// implementedInApiVersion,
-// nameOf(getAgent),
-// "GET",
-// "/banks/BANK_ID/agents/AGENT_ID",
-// "Get Agent",
-// s"""Get Agent.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// agentJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// AgentNotFound,
-// AgentAccountLinkNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount)
-// )
-//
-// lazy val getAgent: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "agents" :: agentId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (agent, callContext) <- NewStyle.function.getAgentByAgentId(agentId, cc.callContext)
-// (agentAccountLinks, callContext) <- NewStyle.function.getAgentAccountLinksByAgentId(agentId, callContext)
-// agentAccountLink <- NewStyle.function.tryons(AgentAccountLinkNotFound, 400, callContext) {
-// agentAccountLinks.head
-// }
-// (bankAccount, callContext) <- NewStyle.function.getBankAccount(BankId(agentAccountLink.bankId), AccountId(agentAccountLink.accountId), callContext)
-// } yield {
-// (JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createNonPersonalUserAttribute,
-// implementedInApiVersion,
-// nameOf(createNonPersonalUserAttribute),
-// "POST",
-// "/users/USER_ID/non-personal/attributes",
-// "Create Non Personal User Attribute",
-// s""" Create Non Personal User Attribute
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// userAttributeJsonV510,
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canCreateNonPersonalUserAttribute))
-// )
-//
-// lazy val createNonPersonalUserAttribute: OBPEndpoint = {
-// case "users" :: userId ::"non-personal":: "attributes" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV510 "
-// for {
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[UserAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
-// user.userId,
-// None,
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// false,
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// deleteNonPersonalUserAttribute,
-// implementedInApiVersion,
-// nameOf(deleteNonPersonalUserAttribute),
-// "DELETE",
-// "/users/USER_ID/non-personal/attributes/USER_ATTRIBUTE_ID",
-// "Delete Non Personal User Attribute",
-// s"""Delete the Non Personal User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canDeleteNonPersonalUserAttribute)))
-//
-// lazy val deleteNonPersonalUserAttribute: OBPEndpoint = {
-// case "users" :: userId :: "non-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// (deleted,callContext) <- Connector.connector.vend.deleteUserAttribute(
-// userAttributeId: String,
-// callContext: Option[CallContext]
-// ) map {
-// i => (connectorEmptyResponse (i._1, callContext), i._2)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getNonPersonalUserAttributes,
-// implementedInApiVersion,
-// nameOf(getNonPersonalUserAttributes),
-// "GET",
-// "/users/USER_ID/non-personal/attributes",
-// "Get Non Personal User Attributes",
-// s"""Get Non Personal User Attribute for a user specified by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetNonPersonalUserAttributes)))
-//
-// lazy val getNonPersonalUserAttributes: OBPEndpoint = {
-// case "users" :: userId :: "non-personal" ::"attributes" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- authenticatedAccess(cc)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// (userAttributes,callContext) <- NewStyle.function.getNonPersonalUserAttributes(
-// user.userId,
-// callContext,
-// )
-// } yield {
-// (JSONFactory510.createUserAttributesJson(userAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// syncExternalUser,
-// implementedInApiVersion,
-// nameOf(syncExternalUser),
-// "POST",
-// "/users/PROVIDER/PROVIDER_ID/sync",
-// "Sync User",
-// s"""The endpoint is used to create or sync an OBP User with User from an external identity provider.
-// |PROVIDER is the host of the provider e.g. a Keycloak Host.
-// |PROVIDER_ID is the unique identifier for the User at the PROVIDER.
-// |At the end of the process, a User will exist in OBP with the Account Access records defined by the CBS.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// refresUserJson,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canSyncUser))
-// )
-//
-// lazy val syncExternalUser : OBPEndpoint = {
-// case "users" :: provider :: providerId :: "sync" :: Nil JsonPost _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user: User, callContext) <- NewStyle.function.getOrCreateResourceUser(provider, providerId, cc.callContext)
-// _ <- AuthUser.refreshUser(user, callContext)
-// } yield {
-// (JSONFactory510.getSyncedUser(user), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountsHeldByUserAtBank,
-// implementedInApiVersion,
-// nameOf(getAccountsHeldByUserAtBank),
-// "GET",
-// "/users/USER_ID/banks/BANK_ID/accounts-held",
-// "Get Accounts Held By User",
-// s"""Get Accounts held by the User if even the User has not been assigned the owner View yet.
-// |
-// |Can be used to onboard the account to the API - since all other account and transaction endpoints require views to be assigned.
-// |
-// |${accountTypeFilterText("/users/USER_ID/banks/BANK_ID/accounts-held")}
-// |
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// coreAccountsHeldJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canGetAccountsHeldAtOneBank, canGetAccountsHeldAtAnyBank))
-// )
-//
-// lazy val getAccountsHeldByUserAtBank: OBPEndpoint = {
-// case "users" :: userId :: "banks" :: BankId(bankId) :: "accounts-held" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (u, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
-// (availableAccounts, callContext) <- NewStyle.function.getAccountsHeld(bankId, u, callContext)
-// (accounts, callContext) <- NewStyle.function.getBankAccountsHeldFuture(availableAccounts.toList, callContext)
-//
-// accountHelds <- getFilteredCoreAccounts(availableAccounts, req, callContext).map { it =>
-// val coreAccountIds: List[String] = it._1.map(_.id)
-// accounts.filter(accountHeld => coreAccountIds.contains(accountHeld.id))
-// }
-// } yield {
-// (JSONFactory300.createCoreAccountsByCoreAccountsJSON(accountHelds), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountsHeldByUser,
-// implementedInApiVersion,
-// nameOf(getAccountsHeldByUser),
-// "GET",
-// "/users/USER_ID/accounts-held",
-// "Get Accounts Held By User",
-// s"""Get Accounts held by the User if even the User has not been assigned the owner View yet.
-// |
-// |Can be used to onboard the account to the API - since all other account and transaction endpoints require views to be assigned.
-// |
-// |${accountTypeFilterText("/users/USER_ID/accounts-held")}
-// |
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// coreAccountsHeldJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canGetAccountsHeldAtAnyBank))
-// )
-//
-// lazy val getAccountsHeldByUser: OBPEndpoint = {
-// case "users" :: userId :: "accounts-held" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (u, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
-// (availableAccounts, callContext) <- NewStyle.function.getAccountsHeldByUser(u, callContext)
-// (accounts, callContext) <- NewStyle.function.getBankAccountsHeldFuture(availableAccounts, callContext)
-//
-// accountHelds <- getFilteredCoreAccounts(availableAccounts, req, callContext).map { it =>
-// val coreAccountIds: List[String] = it._1.map(_.id)
-// accounts.filter(accountHeld => coreAccountIds.contains(accountHeld.id))
-// }
-// } yield {
-// (JSONFactory300.createCoreAccountsByCoreAccountsJSON(accountHelds), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getEntitlementsAndPermissions,
-// implementedInApiVersion,
-// nameOf(getEntitlementsAndPermissions),
-// "GET",
-// "/users/USER_ID/entitlements-and-permissions",
-// "Get Entitlements and Permissions for a User",
-// s"""
-// |
-// |
-// """.stripMargin,
-// EmptyBody,
-// userJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UserHasMissingRoles,
-// UnknownError),
-// List(apiTagRole, apiTagEntitlement, apiTagUser),
-// Some(List(canGetEntitlementsForAnyUserAtAnyBank)))
-//
-//
-// lazy val getEntitlementsAndPermissions: OBPEndpoint = {
-// case "users" :: userId :: "entitlements-and-permissions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
-// entitlements <- NewStyle.function.getEntitlementsByUserId(userId, callContext)
-// } yield {
-// val permissions: Option[Permission] = Views.views.vend.getPermissionForUser(user).toOption
-// (JSONFactory300.createUserInfoJSON (user, entitlements, permissions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// customViewNamesCheck,
-// implementedInApiVersion,
-// nameOf(customViewNamesCheck),
-// "GET",
-// "/management/system/integrity/custom-view-names-check",
-// "Check Custom View Names",
-// s"""Check custom view names.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// CheckSystemIntegrityJsonV510(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemIntegrity),
-// Some(canGetSystemIntegrity :: Nil)
-// )
-//
-// lazy val customViewNamesCheck: OBPEndpoint = {
-// case "management" :: "system" :: "integrity" :: "custom-view-names-check" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// incorrectViews: List[ViewDefinition] <- Future {
-// ViewDefinition.getCustomViews().filter { view =>
-// view.viewId.value.startsWith("_") == false
-// }
-// }
-// } yield {
-// (JSONFactory510.getCustomViewNamesCheck(incorrectViews), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// systemViewNamesCheck,
-// implementedInApiVersion,
-// nameOf(systemViewNamesCheck),
-// "GET",
-// "/management/system/integrity/system-view-names-check",
-// "Check System View Names",
-// s"""Check system view names.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// CheckSystemIntegrityJsonV510(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemIntegrity),
-// Some(canGetSystemIntegrity :: Nil)
-// )
-//
-// lazy val systemViewNamesCheck: OBPEndpoint = {
-// case "management" :: "system" :: "integrity" :: "system-view-names-check" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// incorrectViews: List[ViewDefinition] <- Future {
-// ViewDefinition.getSystemViews().filter { view =>
-// view.viewId.value.startsWith("_") == true
-// }
-// }
-// } yield {
-// (JSONFactory510.getSystemViewNamesCheck(incorrectViews), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// accountAccessUniqueIndexCheck,
-// implementedInApiVersion,
-// nameOf(accountAccessUniqueIndexCheck),
-// "GET",
-// "/management/system/integrity/account-access-unique-index-1-check",
-// "Check Unique Index at Account Access",
-// s"""Check unique index at account access table.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// CheckSystemIntegrityJsonV510(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemIntegrity),
-// Some(canGetSystemIntegrity :: Nil)
-// )
-//
-// lazy val accountAccessUniqueIndexCheck: OBPEndpoint = {
-// case "management" :: "system" :: "integrity" :: "account-access-unique-index-1-check" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// groupedRows: Map[String, List[AccountAccess]] <- Future {
-// AccountAccess.findAll().groupBy { a =>
-// s"${a.bank_id.get}-${a.account_id.get}-${a.view_id.get}-${a.user_fk.get}-${a.consumer_id.get}"
-// }.filter(_._2.size > 1) // Extract only duplicated rows
-// }
-// } yield {
-// (JSONFactory510.getAccountAccessUniqueIndexCheck(groupedRows), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// accountCurrencyCheck,
-// implementedInApiVersion,
-// nameOf(accountCurrencyCheck),
-// "GET",
-// "/management/system/integrity/banks/BANK_ID/account-currency-check",
-// "Check for Sensible Currencies",
-// s"""Check for sensible currencies at Bank Account model
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// CheckSystemIntegrityJsonV510(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemIntegrity),
-// Some(canGetSystemIntegrity :: Nil)
-// )
-//
-// lazy val accountCurrencyCheck: OBPEndpoint = {
-// case "management" :: "system" :: "integrity" :: "banks" :: BankId(bankId) :: "account-currency-check" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// currencies: List[String] <- Future {
-// MappedBankAccount.findAll().map(_.accountCurrency.get).distinct
-// }
-// (bankCurrencies, callContext) <- NewStyle.function.getCurrentCurrencies(bankId, cc.callContext)
-// } yield {
-// (JSONFactory510.getSensibleCurrenciesCheck(bankCurrencies, currencies), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCurrenciesAtBank,
-// implementedInApiVersion,
-// nameOf(getCurrenciesAtBank),
-// "GET",
-// "/banks/BANK_ID/currencies",
-// "Get Currencies at a Bank",
-// """Get Currencies specified by BANK_ID
-// |
-// """.stripMargin,
-// EmptyBody,
-// currenciesJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagFx)
-// )
-//
-// lazy val getCurrenciesAtBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "currencies" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanReadFx, cc=cc.callContext) {
-// checkScope(bankId.value, getConsumerPrimaryKey(cc.callContext), ApiRole.canReadFx)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (currencies, callContext) <- NewStyle.function.getCurrentCurrencies(bankId, callContext)
-// } yield {
-// val json = CurrenciesJsonV510(currencies.map(CurrencyJsonV510(_)))
-// (json, HttpCode.`200`(callContext))
-// }
-//
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// orphanedAccountCheck,
-// implementedInApiVersion,
-// nameOf(orphanedAccountCheck),
-// "GET",
-// "/management/system/integrity/banks/BANK_ID/orphaned-account-check",
-// "Check for Orphaned Accounts",
-// s"""Check for orphaned accounts at Bank Account model
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// CheckSystemIntegrityJsonV510(true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemIntegrity),
-// Some(canGetSystemIntegrity :: Nil)
-// )
-//
-// lazy val orphanedAccountCheck: OBPEndpoint = {
-// case "management" :: "system" :: "integrity" :: "banks" :: BankId(bankId) :: "orphaned-account-check" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// accountAccesses: List[String] <- Future {
-// AccountAccess.findAll(By(AccountAccess.bank_id, bankId.value)).map(_.account_id.get)
-// }
-// bankAccounts <- Future {
-// MappedBankAccount.findAll(By(MappedBankAccount.bank, bankId.value)).map(_.accountId.value)
-// }
-// } yield {
-// val orphanedAccounts: List[String] = accountAccesses.filterNot { accountAccess =>
-// bankAccounts.contains(accountAccess)
-// }
-// (JSONFactory510.getOrphanedAccountsCheck(orphanedAccounts), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-//
-//
-//
-//
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createAtmAttribute,
-// implementedInApiVersion,
-// nameOf(createAtmAttribute),
-// "POST",
-// "/banks/BANK_ID/atms/ATM_ID/attributes",
-// "Create ATM Attribute",
-// s""" Create ATM Attribute
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// atmAttributeJsonV510,
-// atmAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM, apiTagAtmAttribute, apiTagAttribute),
-// Some(List(canCreateAtmAttribute, canCreateAtmAttributeAtAnyBank))
-// )
-//
-// lazy val createAtmAttribute : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: "attributes" :: Nil JsonPost json -> _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AtmAttributeJsonV510 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AtmAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AtmAttributeType.DOUBLE}(12.1234), ${AtmAttributeType.STRING}(TAX_NUMBER), ${AtmAttributeType.INTEGER}(123) and ${AtmAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// bankAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// AtmAttributeType.withName(postedData.`type`)
-// }
-// (atmAttribute, callContext) <- NewStyle.function.createOrUpdateAtmAttribute(
-// bankId,
-// atmId,
-// None,
-// postedData.name,
-// bankAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (JSONFactory510.createAtmAttributeJson(atmAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// getAgents,
-// implementedInApiVersion,
-// nameOf(getAgents),
-// "GET",
-// "/banks/BANK_ID/agents",
-// "Get Agents at Bank",
-// s"""Get Agents at Bank.
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |${urlParametersDocument(true, true)}
-// |""".stripMargin,
-// EmptyBody,
-// minimalAgentsJsonV510,
-// List(
-// $BankNotFound,
-// AgentsNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount)
-// )
-//
-// lazy val getAgents: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "agents" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
-// (agents, callContext) <- NewStyle.function.getAgents(bankId.value, requestParams, callContext)
-// } yield {
-// (JSONFactory510.createMinimalAgentsJson(agents), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAtmAttributes,
-// implementedInApiVersion,
-// nameOf(getAtmAttributes),
-// "GET",
-// "/banks/BANK_ID/atms/ATM_ID/attributes",
-// "Get ATM Attributes",
-// s""" Get ATM Attributes
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// atmAttributesResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM, apiTagAtmAttribute, apiTagAttribute),
-// Some(List(canGetAtmAttribute, canGetAtmAttributeAtAnyBank))
-// )
-//
-// lazy val getAtmAttributes : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: "attributes" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// (attributes, callContext) <- NewStyle.function.getAtmAttributesByAtm(bankId, atmId, callContext)
-// } yield {
-// (JSONFactory510.createAtmAttributesJson(attributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAtmAttribute,
-// implementedInApiVersion,
-// nameOf(getAtmAttribute),
-// "GET",
-// "/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID",
-// "Get ATM Attribute By ATM_ATTRIBUTE_ID",
-// s""" Get ATM Attribute By ATM_ATTRIBUTE_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// atmAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM, apiTagAtmAttribute, apiTagAttribute),
-// Some(List(canGetAtmAttribute, canGetAtmAttributeAtAnyBank))
-// )
-//
-// lazy val getAtmAttribute : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: "attributes" :: atmAttributeId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// (attribute, callContext) <- NewStyle.function.getAtmAttributeById(atmAttributeId, callContext)
-// } yield {
-// (JSONFactory510.createAtmAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtmAttribute,
-// implementedInApiVersion,
-// nameOf(updateAtmAttribute),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID",
-// "Update ATM Attribute",
-// s""" Update ATM Attribute.
-// |
-// |Update an ATM Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// atmAttributeJsonV510,
-// atmAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagATM, apiTagAtmAttribute, apiTagAttribute),
-// Some(List(canUpdateAtmAttribute, canUpdateAtmAttributeAtAnyBank))
-// )
-//
-// lazy val updateAtmAttribute : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: "attributes" :: atmAttributeId :: Nil JsonPut json -> _ =>{
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $AtmAttributeJsonV510 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[AtmAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${AtmAttributeType.DOUBLE}(12.1234), ${AtmAttributeType.STRING}(TAX_NUMBER), ${AtmAttributeType.INTEGER}(123) and ${AtmAttributeType.DATE_WITH_DAY}(2012-04-23)"
-// atmAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// AtmAttributeType.withName(postedData.`type`)
-// }
-// (_, callContext) <- NewStyle.function.getAtmAttributeById(atmAttributeId, cc.callContext)
-// (atmAttribute, callContext) <- NewStyle.function.createOrUpdateAtmAttribute(
-// bankId,
-// atmId,
-// Some(atmAttributeId),
-// postedData.name,
-// atmAttributeType,
-// postedData.value,
-// postedData.is_active,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// (JSONFactory510.createAtmAttributeJson(atmAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAtmAttribute,
-// implementedInApiVersion,
-// nameOf(deleteAtmAttribute),
-// "DELETE",
-// "/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID",
-// "Delete ATM Attribute",
-// s""" Delete ATM Attribute
-// |
-// |Delete a Atm Attribute by its id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagATM, apiTagAtmAttribute, apiTagAttribute),
-// Some(List(canDeleteAtmAttribute, canDeleteAtmAttributeAtAnyBank))
-// )
-//
-// lazy val deleteAtmAttribute : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: "attributes" :: atmAttributeId :: Nil JsonDelete _=> {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// (atmAttribute, callContext) <- NewStyle.function.deleteAtmAttribute(atmAttributeId, callContext)
-// } yield {
-// (Full(atmAttribute), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsentStatusByConsent,
-// implementedInApiVersion,
-// nameOf(updateConsentStatusByConsent),
-// "PUT",
-// "/management/banks/BANK_ID/consents/CONSENT_ID",
-// "Update Consent Status by CONSENT_ID",
-// s"""
-// |
-// |
-// |This endpoint is used to update the Status of Consent.
-// |
-// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(", ")}.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PutConsentStatusJsonV400(status = "AUTHORISED"),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "AUTHORISED"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// ConsentNotFound,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: Nil,
-// Some(List(canUpdateConsentStatusAtOneBank, canUpdateConsentStatusAtAnyBank))
-// )
-//
-// lazy val updateConsentStatusByConsent: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "consents" :: consentId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consentJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutConsentStatusJsonV400 ", 400, cc.callContext) {
-// json.extract[PutConsentStatusJsonV400]
-// }
-// _ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, cc.callContext, s"$ConsentNotFound ($consentId)", 404)
-// }
-// status = ConsentStatus.withName(consentJson.status)
-// consent <- Future(Consents.consentProvider.vend.updateConsentStatus(consentId, status)) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsentAccountAccessByConsentId,
-// implementedInApiVersion,
-// nameOf(updateConsentAccountAccessByConsentId),
-// "PUT",
-// "/management/banks/BANK_ID/consents/CONSENT_ID/account-access",
-// "Update Consent Account Access by CONSENT_ID",
-// s"""
-// |
-// |This endpoint is used to update the Account Access of Consent.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PutConsentPayloadJsonV510(
-// access = ConsentAccessJson(
-// accounts = Option(List(ConsentAccessAccountsJson(
-// iban = Some(ExampleValue.ibanExample.value),
-// bban = None,
-// pan = None,
-// maskedPan = None,
-// msisdn = None,
-// currency = None,
-// )))
-// )
-// ),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "AUTHORISED"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// ConsentNotFound,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: Nil,
-// Some(List(canUpdateConsentAccountAccessAtOneBank, canUpdateConsentAccountAccessAtAnyBank))
-// )
-//
-// lazy val updateConsentAccountAccessByConsentId: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "consents" :: consentId :: "account-access" :: Nil JsonPut json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consent: MappedConsent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, cc.callContext, s"$ConsentNotFound ($consentId)", 404)
-// }
-// consentJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutConsentPayloadJsonV510 ", 400, cc.callContext) {
-// json.extract[PutConsentPayloadJsonV510]
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidJsonFormat The Json body should be the $PutConsentPayloadJsonV510 ",400, cc.callContext) {
-// // Add custom validation
-// !{
-// consentJson.access.accounts.isEmpty &&
-// consentJson.access.balances.isEmpty &&
-// consentJson.access.transactions.isEmpty
-// }
-// }
-// consentJWT <- Consent.updateAccountAccessOfBerlinGroupConsentJWT(
-// consentJson.access,
-// consent,
-// cc.callContext
-// ) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// updatedConsent <- Future(Consents.consentProvider.vend.setJsonWebToken(consent.consentId, consentJWT)) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// } yield {
-// (
-// ConsentJsonV310(
-// updatedConsent.consentId,
-// updatedConsent.jsonWebToken,
-// updatedConsent.status
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsentUserIdByConsentId,
-// implementedInApiVersion,
-// nameOf(updateConsentUserIdByConsentId),
-// "PUT",
-// "/management/banks/BANK_ID/consents/CONSENT_ID/created-by-user",
-// "Update Created by User of Consent by CONSENT_ID",
-// s"""
-// |
-// |This endpoint is used to Update the User bound to a consent.
-// |
-// |In general we would not expect for a management user to set the User bound to a consent, but there may be
-// |some use cases where this workflow is useful.
-// |
-// |If successful, the "Created by User ID" field in the OBP Consent table will be updated.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PutConsentUserJsonV400(user_id = "ed7a7c01-db37-45cc-ba12-0ae8891c195c"),
-// ConsentChallengeJsonV310(
-// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
-// jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
-// status = "AUTHORISED"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// ConsentNotFound,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: Nil,
-// Some(List(canUpdateConsentUserAtOneBank, canUpdateConsentUserAtAnyBank))
-// )
-//
-// lazy val updateConsentUserIdByConsentId: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "consents" :: consentId :: "created-by-user" :: Nil JsonPut json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consent: MappedConsent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, cc.callContext, s"$ConsentNotFound ($consentId)", 404)
-// }
-// consentJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutConsentUserJsonV400 ", 400, cc.callContext) {
-// json.extract[PutConsentUserJsonV400]
-// }
-// user <- Users.users.vend.getUserByUserIdFuture(consentJson.user_id) map {
-// x => unboxFullOrFail(x, cc.callContext, s"$UserNotFoundByUserId Current UserId(${consentJson.user_id})")
-// }
-// consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// _ <- Helper.booleanToFuture(ConsentUserAlreadyAdded, cc = cc.callContext) {
-// Option(consent.userId).forall(_.isBlank) // checks whether userId is not populated
-// }
-// consent <- Future(Consents.consentProvider.vend.updateConsentUser(consentId, user)) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// consentJWT <- Future(Consent.updateUserIdOfBerlinGroupConsentJWT(
-// consentJson.user_id,
-// consent,
-// cc.callContext
-// )) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// updatedConsent <- Future(Consents.consentProvider.vend.setJsonWebToken(consent.consentId, consentJWT)) map {
-// i => connectorEmptyResponse(i, cc.callContext)
-// }
-// } yield {
-// (
-// ConsentJsonV310(
-// updatedConsent.consentId,
-// updatedConsent.jsonWebToken,
-// updatedConsent.status
-// ),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getMyConsentsByBank,
-// implementedInApiVersion,
-// nameOf(getMyConsentsByBank),
-// "GET",
-// "/banks/BANK_ID/my/consents",
-// "Get My Consents at Bank",
-// s"""
-// |
-// |This endpoint gets the Consents created by a current User at the specified Bank.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |3 status (ignore if omitted)
-// |
-// |4 sort_by (defaults to created_date:desc) eg: sort_by=created_date:desc
-// |
-// |Note: This endpoint only returns consents that explicitly reference the specified BANK_ID.
-// |Consents created before the consent_item join table was introduced will not appear in results.
-// |
-// |eg: /banks/BANK_ID/my/consents?limit=10&offset=0&sort_by=created_date:desc
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsInfoJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val getMyConsentsByBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val url = cc.url
-// val limitParam = getHttpRequestUrlParam(url, "limit") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
-// case _ => 50
-// }
-// val offsetParam = getHttpRequestUrlParam(url, "offset") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
-// case _ => 0
-// }
-// val statusParam = getHttpRequestUrlParam(url, "status") match {
-// case s if s.nonEmpty => Some(s)
-// case _ => None
-// }
-// val sortByParam = getHttpRequestUrlParam(url, "sort_by") match {
-// case s if s.nonEmpty => s
-// case _ => "created_date:desc"
-// }
-// val sortParts = sortByParam.split(":").map(_.trim.toLowerCase)
-// val sortField = sortParts(0)
-// val sortDirection = sortParts.lift(1).getOrElse("desc")
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// rows <- Future {
-// DoobieConsentQueries.getConsentsByUserAndBank(
-// userId = u.userId,
-// bankId = bankId.value,
-// status = statusParam,
-// limit = limitParam,
-// offset = offsetParam,
-// sortField = sortField,
-// sortDirection = sortDirection
-// )
-// }
-// } yield {
-// val consents = rows.map(rowToConsentInfoJsonV510)
-// (ConsentsInfoJsonV510(consents), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyConsents,
-// implementedInApiVersion,
-// nameOf(getMyConsents),
-// "GET",
-// "/my/consents",
-// "Get My Consents",
-// s"""
-// |
-// |This endpoint gets the Consents created by the current User.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |3 status (ignore if omitted)
-// |
-// |4 sort_by (defaults to created_date:desc) eg: sort_by=created_date:desc
-// |
-// |eg: /my/consents?limit=10&offset=0&sort_by=created_date:desc
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsInfoJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val getMyConsents: OBPEndpoint = {
-// case "my" :: "consents" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val url = cc.url
-// val limitParam = getHttpRequestUrlParam(url, "limit") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
-// case _ => 50
-// }
-// val offsetParam = getHttpRequestUrlParam(url, "offset") match {
-// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
-// case _ => 0
-// }
-// val statusParam = getHttpRequestUrlParam(url, "status") match {
-// case s if s.nonEmpty => Some(s)
-// case _ => None
-// }
-// val sortByParam = getHttpRequestUrlParam(url, "sort_by") match {
-// case s if s.nonEmpty => s
-// case _ => "created_date:desc"
-// }
-// val sortParts = sortByParam.split(":").map(_.trim.toLowerCase)
-// val sortField = sortParts(0)
-// val sortDirection = sortParts.lift(1).getOrElse("desc")
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// rows <- Future {
-// DoobieConsentQueries.getConsentsByUser(
-// userId = u.userId,
-// status = statusParam,
-// limit = limitParam,
-// offset = offsetParam,
-// sortField = sortField,
-// sortDirection = sortDirection
-// )
-// }
-// } yield {
-// (ConsentsInfoJsonV510(rows.map(rowToConsentInfoJsonV510)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// private def rowToConsentInfoJsonV510(row: DoobieConsentQueries.ConsentRow): ConsentInfoJsonV510 = {
-// ConsentInfoJsonV510(
-// consent_reference_id = row.consentReferenceId.toString,
-// consent_id = row.consentId,
-// consumer_id = row.consumerId.orNull,
-// created_by_user_id = row.createdByUserId,
-// status = row.status,
-// last_action_date =
-// row.lastActionDate.map(d => new java.text.SimpleDateFormat(DateWithDay).format(d)).orNull,
-// last_usage_date =
-// row.lastUsageDate.map(d => new java.text.SimpleDateFormat(DateWithSeconds).format(d)).orNull,
-// jwt = row.jwt.orNull,
-// jwt_payload = row.jwtPayload.orNull,
-// api_standard = row.apiStandard.orNull,
-// api_version = row.apiVersion.orNull,
-// jwt_expires_at = row.jwtExpiresAt.map(d => new java.text.SimpleDateFormat(DateWithSeconds).format(d)).orNull
-// )
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentsAtBank,
-// implementedInApiVersion,
-// nameOf(getConsentsAtBank),
-// "GET",
-// "/management/consents/banks/BANK_ID",
-// "Get Consents at Bank",
-// s"""
-// |
-// |This endpoint gets the Consents at Bank by BANK_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |3 consumer_id (ignore if omitted)
-// |
-// |4 user_id (ignore if omitted)
-// |
-// |5 status (ignore if omitted)
-// |
-// |eg: /management/consents/banks/BANK_ID?&consumer_id=78&limit=10&offset=10
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2),
-// Some(List(canGetConsentsAtOneBank, canGetConsentsAtAnyBank)),
-// )
-//
-// lazy val getConsentsAtBank: OBPEndpoint = {
-// case "management" :: "consents" :: "banks" :: BankId(bankId) :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, cc.callContext)
-// (consents, totalPages) <- Future {
-// Consents.consentProvider.vend.getConsents(obpQueryParams)
-// }
-// } yield {
-// val consentsOfBank = Consent.filterByBankId(consents, bankId)
-// (createConsentsJsonV510(consentsOfBank, totalPages), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsents,
-// implementedInApiVersion,
-// nameOf(getConsents),
-// "GET",
-// "/management/consents",
-// "Get Consents",
-// s"""
-// |
-// |This endpoint gets the Consents.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |1 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |3 consumer_id (ignore if omitted)
-// |
-// |4 consent_id (ignore if omitted)
-// |
-// |5 user_id (ignore if omitted)
-// |
-// |6 status (ignore if omitted)
-// |
-// |7 bank_id (ignore if omitted)
-// |
-// |8 provider_provider_id (ignore if omitted)
-// |provider and provider_id values are separated by pipe char
-// |eg: provider_provider_id=http%3A%2F%2Flocalhost%3A7070%2Frealms%2Fmaster|7837ee9c-3446-4d8c-9b90-301a52b4851d
-// |
-// |eg:/management/consents?consumer_id=78&limit=10&offset=10
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentsJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2),
-// Some(List(canGetConsentsAtAnyBank)),
-// )
-//
-// lazy val getConsents: OBPEndpoint = {
-// case "management" :: "consents" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, cc.callContext)
-// (consents, totalPages) <- Future {
-// Consents.consentProvider.vend.getConsents(obpQueryParams)
-// }
-// } yield {
-// (createConsentsJsonV510(consents, totalPages), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentByConsentId,
-// implementedInApiVersion,
-// nameOf(getConsentByConsentId),
-// "GET",
-// "/user/current/consents/CONSENT_ID",
-// "Get Consent By Consent Id via User",
-// s"""
-// |
-// |This endpoint gets the Consent By consent id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-// lazy val getConsentByConsentId: OBPEndpoint = {
-// case "user" :: "current" :: "consents" :: consentId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// consent <- Future { Consents.consentProvider.vend.getConsentByConsentId(consentId)} map {
-// unboxFullOrFail(_, cc.callContext, ConsentNotFound, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, failCode = 404, cc = cc.callContext) {
-// consent.mUserId == cc.userId
-// }
-// } yield {
-// (JSONFactory510.getConsentInfoJson(consent), HttpCode.`200`(cc))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getConsentByConsentIdViaConsumer,
-// implementedInApiVersion,
-// nameOf(getConsentByConsentIdViaConsumer),
-// "GET",
-// "/consumer/current/consents/CONSENT_ID",
-// "Get Consent By Consent Id via Consumer",
-// s"""
-// |
-// |This endpoint gets the Consent By consent id.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// consentJsonV500,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-// lazy val getConsentByConsentIdViaConsumer: OBPEndpoint = {
-// case "consumer" :: "current" :: "consents" :: consentId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// consent <- Future { Consents.consentProvider.vend.getConsentByConsentId(consentId)} map {
-// unboxFullOrFail(_, cc.callContext, ConsentNotFound, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, failCode = 404, cc = cc.callContext) {
-// consent.mConsumerId.get == cc.consumer.map(_.consumerId.get).getOrElse("None")
-// }
-// } yield {
-// (JSONFactory510.getConsentInfoJson(consent), HttpCode.`200`(cc))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// revokeConsentAtBank,
-// implementedInApiVersion,
-// nameOf(revokeConsentAtBank),
-// "DELETE",
-// "/banks/BANK_ID/consents/CONSENT_ID",
-// "Revoke Consent at Bank",
-// s"""
-// |Revoke Consent specified by CONSENT_ID
-// |
-// |There are a few reasons you might need to revoke an application’s access to a user’s account:
-// | - The user explicitly wishes to revoke the application’s access
-// | - You as the service provider have determined an application is compromised or malicious, and want to disable it
-// | - etc.
-// ||
-// |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.
-// |The status of the token is changed to "REVOKED" so the next time the revoked client makes a request, their token will fail to validate.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// revokedConsentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2),
-// Some(List(canRevokeConsentAtBank))
-// )
-//
-// lazy val revokeConsentAtBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "consents" :: consentId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, callContext, ConsentNotFound)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, cc=callContext) {
-// consent.mUserId == user.userId
-// }
-// consent <- Future(Consents.consentProvider.vend.revoke(consentId)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// selfRevokeConsent,
-// implementedInApiVersion,
-// nameOf(selfRevokeConsent),
-// "DELETE",
-// "/my/consent/current",
-// "Revoke Consent used in the Current Call",
-// s"""
-// |Revoke Consent specified by Consent-Id at Request Header
-// |
-// |There are a few reasons you might need to revoke an application’s access to a user’s account:
-// | - The user explicitly wishes to revoke the application’s access
-// | - You as the service provider have determined an application is compromised or malicious, and want to disable it
-// | - etc.
-// ||
-// |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.
-// |The status of the token is changed to "REVOKED" so the next time the revoked client makes a request, their token will fail to validate.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// revokedConsentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)
-// )
-// lazy val selfRevokeConsent: OBPEndpoint = {
-// case "my" :: "consent" :: "current" :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// consentId = getConsentIdRequestHeaderValue(cc.requestHeaders).getOrElse("")
-// _ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, callContext, ConsentNotFound, 404)
-// }
-// consent <- Future(Consents.consentProvider.vend.revoke(consentId)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// revokeMyConsent,
-// implementedInApiVersion,
-// nameOf(revokeMyConsent),
-// "Delete",
-// "/my/consents/CONSENT_ID",
-// "Revoke My Consent",
-// s"""
-// |Revoke Consent for current user specified by CONSENT_ID
-// |
-// |There are a few reasons you might need to revoke an application’s access to a user’s account:
-// | - The user explicitly wishes to revoke the application’s access
-// | - You as the service provider have determined an application is compromised or malicious, and want to disable it
-// | - etc.
-// |
-// |Please note that this endpoint only supports the case:: "The user explicitly wishes to revoke the application’s access"
-// |
-// |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.
-// |The status of the token is changed to "REVOKED" so the next time the revoked client makes a request, their token will fail to validate.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// revokedConsentJsonV310,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2))
-//
-// lazy val revokeMyConsent: OBPEndpoint = {
-// case "my" :: "consents" :: consentId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
-// unboxFullOrFail(_, callContext, ConsentNotFound, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, cc=callContext) {
-// consent.mUserId == user.userId
-// }
-// consent <- Future(Consents.consentProvider.vend.revoke(consentId)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// val generalObpConsentText: String =
-// s"""
-// |
-// |An OBP Consent allows the holder of the Consent to call one or more endpoints.
-// |
-// |Consents must be created and authorisied using SCA (Strong Customer Authentication).
-// |
-// |That is, Consents can be created by an authorised User via the OBP REST API but they must be confirmed via an out of band (OOB) mechanism such as a code sent to a mobile phone.
-// |
-// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(", ")}.
-// |
-// |Each Consent is bound to a consumer i.e. you need to identify yourself over request header value Consumer-Key.
-// |
-// |Examples:
-// |
-// |For example:
-// |GET /obp/v4.0.0/users/current HTTP/1.1
-// |Host: 127.0.0.1:8080
-// |Consent-JWT: eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEFueVVzZXIiLCJiYW5rX2lkIjoiIn
-// |1dLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIzNDc1MDEzZi03YmY5LTQyNj
-// |EtOWUxYy0xZTdlNWZjZTJlN2UiLCJhdWQiOiI4MTVhMGVmMS00YjZhLTQyMDUtYjExMi1lNDVmZDZmNGQzYWQiLCJuYmYiOjE1ODA3NDE2NjcsIml
-// |zcyI6Imh0dHA6XC9cLzEyNy4wLjAuMTo4MDgwIiwiZXhwIjoxNTgwNzQ1MjY3LCJpYXQiOjE1ODA3NDE2NjcsImp0aSI6ImJkYzVjZTk5LTE2ZTY
-// |tNDM4Yi1hNjllLTU3MTAzN2RhMTg3OCIsInZpZXdzIjpbXX0.L3fEEEhdCVr3qnmyRKBBUaIQ7dk1VjiFaEBW8hUNjfg
-// |
-// |Consumer-Key: ejznk505d132ryomnhbx1qmtohurbsbb0kijajsk
-// |cache-control: no-cache
-// |
-// |Maximum time to live of the token is specified over props value consents.max_time_to_live. In case isn't defined default value is 3600 seconds.
-// |
-// |Example of POST JSON:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// | "email": "eveline@example.com",
-// | "valid_from": "2020-02-07T08:43:34Z",
-// | "time_to_live": 3600
-// |}
-// |Please note that only optional fields are: consumer_id, valid_from and time_to_live.
-// |In case you omit they the default values are used:
-// |consumer_id = consumer of current user
-// |valid_from = current time
-// |time_to_live = consents.max_time_to_live
-// |
-// """.stripMargin
-//
-// staticResourceDocs += ResourceDoc(
-// createConsentImplicit,
-// implementedInApiVersion,
-// nameOf(createConsentImplicit),
-// "POST",
-// "/my/consents/IMPLICIT",
-// "Create Consent (IMPLICIT)",
-// s"""
-// |
-// |This endpoint starts the process of creating a Consent.
-// |
-// |The Consent is created in an ${ConsentStatus.INITIATED} state.
-// |
-// |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
-// |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
-// |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
-// |
-// |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
-// |
-// |$generalObpConsentText
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Example 1:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// |}
-// |
-// |Please note that consumer_id is optional field
-// |Example 2:
-// |{
-// | "everything": true,
-// | "views": [],
-// | "entitlements": [],
-// |}
-// |
-// |Please note if everything=false you need to explicitly specify views and entitlements
-// |Example 3:
-// |{
-// | "everything": false,
-// | "views": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
-// | }
-// | ],
-// | "entitlements": [
-// | {
-// | "bank_id": "GENODEM1GLS",
-// | "role_name": "CanGetCustomersAtOneBank"
-// | }
-// | ],
-// | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// |}
-// |
-// |""",
-// postConsentImplicitJsonV310,
-// consentJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// InvalidJsonFormat,
-// ConsentAllowedScaMethods,
-// RolesAllowedInConsent,
-// ViewsAllowedInConsent,
-// ConsumerNotFoundByConsumerId,
-// ConsumerIsDisabled,
-// MissingPropsValueAtThisInstance,
-// SmsServerNotResponding,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
-//
-// lazy val createConsentImplicit = createConsent
-//
-// lazy val createConsent: OBPEndpoint = {
-// case "my" :: "consents" :: scaMethod :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc = callContext) {
-// List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod)
-// }
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
-// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentBodyCommonJson]
-// }
-// maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty = "consents.max_time_to_live", defaultValue = 3600)
-// _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc = callContext) {
-// consentJson.time_to_live match {
-// case Some(ttl) => ttl <= maxTimeToLive
-// case _ => true
-// }
-// }
-// requestedEntitlements = consentJson.entitlements
-// myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId)
-// _ = logger.info(s"createConsent says: userId=${user.userId}, userName=${user.name}, requestedEntitlements=${requestedEntitlements.map(re => s"(role_name=${re.role_name}, bank_id=${re.bank_id})")}, myEntitlements=${myEntitlements.getOrElse(Nil).map(e => s"(roleName=${e.roleName}, bankId=${e.bankId})")}")
-// _ = {
-// val myEnts = myEntitlements.getOrElse(Nil)
-// requestedEntitlements.foreach { re =>
-// val matched = myEnts.exists(e => e.roleName == re.role_name && e.bankId == re.bank_id)
-// logger.info(s"createConsent says: checking requested role_name=${re.role_name}, bank_id='${re.bank_id}' => matched=$matched")
-// if (!matched) {
-// myEnts.foreach { e =>
-// logger.info(s"createConsent says: comparing with roleName=${e.roleName}, bankId='${e.bankId}' => nameMatch=${e.roleName == re.role_name}, bankIdMatch=${e.bankId == re.bank_id}")
-// }
-// }
-// }
-// }
-// _ <- Helper.booleanToFuture(RolesAllowedInConsent, cc = callContext) {
-// requestedEntitlements.forall(
-// re => myEntitlements.getOrElse(Nil).exists(
-// e => e.roleName == re.role_name && e.bankId == re.bank_id
-// )
-// )
-// }
-// requestedViews = consentJson.views
-// (_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
-// _ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc = callContext) {
-// requestedViews.forall(
-// rv => assignedViews.exists {
-// e =>
-// e.view_id == rv.view_id &&
-// e.bank_id == rv.bank_id &&
-// e.account_id == rv.account_id
-// }
-// )
-// }
-// (consumerFromRequestBody: Option[Consumer], applicationText) <- consentJson.consumer_id match {
-// case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map {
-// c => (Some(c), c.description)
-// }
-// case None => Future(None, "Any application")
-// }
-//
-//
-// challengeAnswer = Props.mode match {
-// case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
-// case _ => SecureRandomUtil.numeric()
-// }
-// createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None, consumerFromRequestBody)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// consentJWT =
-// Consent.createConsentJWT(
-// user,
-// consentJson,
-// createdConsent.secret,
-// createdConsent.consentId,
-// consumerFromRequestBody.map(_.consumerId.get),
-// consentJson.valid_from,
-// consentJson.time_to_live.getOrElse(3600),
-// None,
-// )
-// _ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// validUntil = Helper.calculateValidTo(consentJson.valid_from, consentJson.time_to_live.getOrElse(3600))
-// _ <- Future(Consents.consentProvider.vend.setValidUntil(createdConsent.consentId, validUntil)) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// //we need to check `skip_consent_sca_for_consumer_id_pairs` props, to see if we really need the SCA flow.
-// //this is from callContext
-// grantorConsumerId = callContext.map(_.consumer.toOption.map(_.consumerId.get)).flatten.getOrElse("Unknown")
-// //this is from json body
-// granteeConsumerId = consentJson.consumer_id.getOrElse("Unknown")
-//
-// // Log consent SCA skip check to ai.log
-// _ <- Future.successful {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] Checking SCA skip for consent creation")
-// println(s"[skip_consent_sca_for_consumer_id_pairs] grantorConsumerId (from callContext): $grantorConsumerId")
-// println(s"[skip_consent_sca_for_consumer_id_pairs] granteeConsumerId (from json body): $granteeConsumerId")
-// println(s"[skip_consent_sca_for_consumer_id_pairs] skipConsentScaForConsumerIdPairs config: ${APIUtil.skipConsentScaForConsumerIdPairs}")
-// }
-//
-// shouldSkipConsentScaForConsumerIdPair = APIUtil.skipConsentScaForConsumerIdPairs.contains(
-// APIUtil.ConsumerIdPair(
-// grantorConsumerId,
-// granteeConsumerId
-// ))
-// _ <- Future.successful {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] shouldSkipConsentScaForConsumerIdPair: $shouldSkipConsentScaForConsumerIdPair")
-// if (!shouldSkipConsentScaForConsumerIdPair) {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] Consumer pair NOT found in skip list. Looking for: ConsumerIdPair(grantor_consumer_id='$grantorConsumerId', grantee_consumer_id='$granteeConsumerId')")
-// println(s"[skip_consent_sca_for_consumer_id_pairs] Available pairs in config: ${APIUtil.skipConsentScaForConsumerIdPairs.map(pair => s"ConsumerIdPair(grantor_consumer_id='${pair.grantor_consumer_id}', grantee_consumer_id='${pair.grantee_consumer_id}')").mkString(", ")}")
-// } else {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] Consumer pair FOUND in skip list - SCA will be skipped")
-// }
-// }
-// mappedConsent <- if (shouldSkipConsentScaForConsumerIdPair) {
-// Future{
-// MappedConsent.find(By(MappedConsent.mConsentId, createdConsent.consentId)).map(_.mStatus(ConsentStatus.ACCEPTED.toString).saveMe()).head
-// }
-// } else {
-// val challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText"
-// scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email
-// for {
-// failMsg <- Future {
-// s"$InvalidJsonFormat The Json body should be the $PostConsentEmailJsonV310"
-// }
-// postConsentEmailJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentEmailJsonV310]
-// }
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.EMAIL,
-// postConsentEmailJson.email,
-// Some("OBP Consent Challenge"),
-// challengeText,
-// callContext
-// )
-// } yield {
-// createdConsent
-// }
-// case v if v == StrongCustomerAuthentication.SMS.toString =>
-// for {
-// failMsg <- Future {
-// s"$InvalidJsonFormat The Json body should be the $PostConsentPhoneJsonV310"
-// }
-// postConsentPhoneJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostConsentPhoneJsonV310]
-// }
-// phoneNumber = postConsentPhoneJson.phone_number
-// (status, callContext) <- NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.SMS,
-// phoneNumber,
-// None,
-// challengeText,
-// callContext
-// )
-// } yield {
-// createdConsent
-// }
-// case v if v == StrongCustomerAuthentication.IMPLICIT.toString =>
-// // For IMPLICIT consents, check if SCA should be skipped first
-// if (shouldSkipConsentScaForConsumerIdPair) {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] IMPLICIT consent auto-accepted due to skip_consent_sca_for_consumer_id_pairs config")
-// Future {
-// MappedConsent.find(By(MappedConsent.mConsentId, createdConsent.consentId)).map(_.mStatus(ConsentStatus.ACCEPTED.toString).saveMe()).head
-// }
-// } else {
-// println(s"[skip_consent_sca_for_consumer_id_pairs] IMPLICIT consent requires SCA - proceeding with implicit SCA flow")
-// for {
-// (consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
-// status <- consentImplicitSCA.scaMethod match {
-// case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
-// NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.EMAIL,
-// consentImplicitSCA.recipient,
-// Some("OBP Consent Challenge"),
-// challengeText,
-// callContext
-// )
-// case v if v == StrongCustomerAuthentication.SMS =>
-// NewStyle.function.sendCustomerNotification(
-// StrongCustomerAuthentication.SMS,
-// consentImplicitSCA.recipient,
-// None,
-// challengeText,
-// callContext
-// )
-// case _ => Future {
-// "Success"
-// }
-// }} yield {
-// createdConsent
-// }
-// }
-// case _ => Future {
-// createdConsent
-// }
-// }
-// }
-// } yield {
-// (ConsentJsonV310(mappedConsent.consentId, consentJWT, mappedConsent.status), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// mtlsClientCertificateInfo,
-// implementedInApiVersion,
-// nameOf(mtlsClientCertificateInfo),
-// "GET",
-// "/my/mtls/certificate/current",
-// "Provide client's certificate info of a current call",
-// s"""
-// |Provide client's certificate info of a current call specified by PSD2-CERT value at Request Header
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// certificateInfoJsonV510,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)
-// )
-// lazy val mtlsClientCertificateInfo: OBPEndpoint = {
-// case "my" :: "mtls" :: "certificate" :: "current" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(_), callContext) <- authenticatedAccess(cc)
-// info <- Future(X509.getCertificateInfo(APIUtil.`getPSD2-CERT`(cc.requestHeaders))) map {
-// unboxFullOrFail(_, callContext, X509GeneralError)
-// }
-// } yield {
-// (info, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateMyApiCollection,
-// implementedInApiVersion,
-// nameOf(updateMyApiCollection),
-// "PUT",
-// "/my/api-collections/API_COLLECTION_ID",
-// "Update My Api Collection By API_COLLECTION_ID",
-// s"""Update Api Collection for logged in user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// postApiCollectionJson400,
-// apiCollectionJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagApiCollection)
-// )
-//
-// lazy val updateMyApiCollection: OBPEndpoint = {
-// case "my" :: "api-collections" :: apiCollectionId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostApiCollectionJson400", 400, cc.callContext) {
-// json.extract[PostApiCollectionJson400]
-// }
-// (_, callContext) <- NewStyle.function.getApiCollectionById(apiCollectionId, cc.callContext)
-// (apiCollection, callContext) <- NewStyle.function.updateApiCollection(
-// apiCollectionId,
-// putJson.api_collection_name,
-// putJson.is_sharable,
-// putJson.description.getOrElse(""),
-// callContext
-// )
-// } yield {
-// (JSONFactory400.createApiCollectionJsonV400(apiCollection), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getUserByProviderAndUsername,
-// implementedInApiVersion,
-// nameOf(getUserByProviderAndUsername),
-// "GET",
-// "/users/provider/PROVIDER/username/USERNAME",
-// "Get User by USERNAME",
-// s"""Get user by PROVIDER and USERNAME
-// |
-// |Get a User by their authentication provider and username.
-// |
-// |**URL Parameters:**
-// |
-// |* PROVIDER - The authentication provider (e.g., http://127.0.0.1:8080, google.com, OBP)
-// |* USERNAME - The username at that provider (e.g., obpstripe, john.doe)
-// |
-// |**Important:** The PROVIDER parameter can contain special characters like slashes and colons.
-// |For example, if the provider is "http://127.0.0.1:8080", the full URL would be:
-// |
-// |`GET /obp/v5.1.0/users/provider/http://127.0.0.1:8080/username/obpstripe`
-// |
-// |The API will correctly parse the provider value even with these special characters.
-// |
-// |**To find valid providers**, use the GET /obp/v6.0.0/providers endpoint (available in API version 6.0.0).
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetAnyUser entitlement is required.
-// |
-// """.stripMargin,
-// EmptyBody,
-// userWithNamesJsonV510,
-// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUserByProviderAndUsername: OBPEndpoint = {
-// case "users" :: "provider" :: provider :: "username" :: username :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// user <- Users.users.vend.getUserByProviderAndUsernameFuture(URLDecoder.decode(provider, StandardCharsets.UTF_8), username) map {
-// x => unboxFullOrFail(x, cc.callContext, UserNotFoundByProviderAndUsername, 404)
-// }
-// entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, cc.callContext)
-// isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
-// authUser = AuthUser.find(By(AuthUser.user, user.userPrimaryKey.value))
-// } yield {
-// (JSONFactory510.createUserWithNamesJSON(
-// user,
-// authUser.map(_.firstName.get).getOrElse(""),
-// authUser.map(_.lastName.get).getOrElse(""),
-// entitlements, None, isLocked
-// ), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getUserLockStatus,
-// implementedInApiVersion,
-// nameOf(getUserLockStatus),
-// "GET",
-// "/users/PROVIDER/USERNAME/lock-status",
-// "Get User Lock Status",
-// s"""
-// |Get User Login Status.
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// badLoginStatusJson,
-// List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
-// List(apiTagUser),
-// Some(List(canReadUserLockedStatus))
-// )
-// lazy val getUserLockStatus: OBPEndpoint = {
-// //get private accounts for all banks
-// case "users" ::provider :: username :: "lock-status" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadUserLockedStatus, callContext)
-// _ <- Users.users.vend.getUserByProviderAndUsernameFuture(provider, username) map {
-// x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404)
-// }
-// badLoginStatus <- Future {
-// LoginAttempt.getOrCreateBadLoginStatus(provider, username)
-// } map {
-// unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
-// }
-// } yield {
-// (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// unlockUserByProviderAndUsername,
-// implementedInApiVersion,
-// nameOf(unlockUserByProviderAndUsername),
-// "PUT",
-// "/users/PROVIDER/USERNAME/lock-status",
-// "Unlock the user",
-// s"""
-// |Unlock a User.
-// |
-// |(Perhaps the user was locked due to multiple failed login attempts)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// badLoginStatusJson,
-// List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
-// List(apiTagUser),
-// Some(List(canUnlockUser)))
-// lazy val unlockUserByProviderAndUsername: OBPEndpoint = {
-// //get private accounts for all banks
-// case "users" :: provider :: username :: "lock-status" :: Nil JsonPut req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUnlockUser, callContext)
-// _ <- Users.users.vend.getUserByProviderAndUsernameFuture(provider, username) map {
-// x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404)
-// }
-// _ <- Future {
-// LoginAttempt.resetBadLoginAttempts(provider, username)
-// }
-// _ <- Future {
-// UserLocksProvider.unlockUser(provider, username)
-// }
-// badLoginStatus <- Future {
-// LoginAttempt.getOrCreateBadLoginStatus(provider, username)
-// } map {
-// unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
-// }
-// } yield {
-// (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// lockUserByProviderAndUsername,
-// implementedInApiVersion,
-// nameOf(lockUserByProviderAndUsername),
-// "POST",
-// "/users/PROVIDER/USERNAME/locks",
-// "Lock the user",
-// s"""
-// |Lock a User.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// userLockStatusJson,
-// List($AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
-// List(apiTagUser),
-// Some(List(canLockUser)))
-// lazy val lockUserByProviderAndUsername: OBPEndpoint = {
-// case "users" :: provider :: username :: "locks" :: Nil JsonPost req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// userLocks <- Future {
-// UserLocksProvider.lockUser(provider, username)
-// } map {
-// unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
-// }
-// } yield {
-// (JSONFactory400.createUserLockStatusJson(userLocks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// validateUserByUserId,
-// implementedInApiVersion,
-// nameOf(validateUserByUserId),
-// "PUT",
-// "/management/users/USER_ID",
-// "Validate a user",
-// s"""
-// |Manually validate a User by USER_ID.
-// |
-// |This is an administrative endpoint that marks a user's account as validated (i.e. sets is_validated to true).
-// |
-// |This is useful when an administrator needs to validate a user on their behalf,
-// |for example if the user did not receive the validation email, or if the email validation token has expired.
-// |
-// |For self-service email validation, see the Validate User Email endpoint (POST /users/email-validation).
-// |
-// |Authentication is Required and the user must have the canValidateUser role.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// UserValidatedJson(is_validated = true),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canValidateUser)))
-// lazy val validateUserByUserId: OBPEndpoint = {
-// case "management" :: "users" :: userId :: Nil JsonPut req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- NewStyle.function.findByUserId(userId, cc.callContext)
-// (userValidated, callContext) <- NewStyle.function.validateUser(user.userPrimaryKey, callContext)
-// } yield {
-// (UserValidatedJson(userValidated.validated.get), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getAggregateMetrics,
-// implementedInApiVersion,
-// nameOf(getAggregateMetrics),
-// "GET",
-// "/management/aggregate-metrics",
-// "Get Aggregate Metrics",
-// s"""Returns aggregate metrics on api usage eg. total count, response time (in ms), etc.
-// |
-// |Should be able to filter on the following fields
-// |
-// |eg: /management/aggregate-metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&consumer_id=5
-// |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount
-// |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions
-// |&verb=GET&anon=false&app_name=MapperPostman
-// |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |1 from_date (defaults to the day before the current date): eg:from_date=$DateWithMsExampleString
-// |
-// |2 to_date (defaults to the current date) eg:to_date=$DateWithMsExampleString
-// |
-// |3 consumer_id (if null ignore)
-// |
-// |4 user_id (if null ignore)
-// |
-// |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |6 url (if null ignore), note: can not contain '&'.
-// |
-// |7 app_name (if null ignore)
-// |
-// |8 implemented_by_partial_function (if null ignore),
-// |
-// |9 implemented_in_version (if null ignore)
-// |
-// |10 verb (if null ignore)
-// |
-// |11 correlation_id (if null ignore)
-// |
-// |12 include_app_names (if null ignore).eg: &include_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |13 include_url_patterns (if null ignore).you can design you own SQL LIKE pattern. eg: &include_url_patterns=%management/metrics%,%management/aggregate-metrics%
-// |
-// |14 include_implemented_by_partial_functions (if null ignore).eg: &include_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics
-// |
-// |15 http_status_code (if null ignore) - Filter by HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// aggregateMetricsJSONV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagAggregateMetrics),
-// Some(List(canReadAggregateMetrics)))
-//
-// lazy val getAggregateMetrics: OBPEndpoint = {
-// case "management" :: "aggregate-metrics" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadAggregateMetrics, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// aggregateMetrics <- APIMetrics.apiMetrics.vend.getAllAggregateMetricsFuture(obpQueryParams,true) map {
-// x => unboxFullOrFail(x, callContext, GetAggregateMetricsError)
-// }
-// } yield {
-// (createAggregateMetricJson(aggregateMetrics), HttpCode.`200`(callContext))
-// }
-// }
-//
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getMetrics,
-// implementedInApiVersion,
-// nameOf(getMetrics),
-// "GET",
-// "/management/metrics",
-// "Get Metrics",
-// s"""Get API metrics rows. These are records of each REST API call.
-// |
-// |require CanReadMetrics role
-// |
-// |**IMPORTANT: Smart Caching & Performance**
-// |
-// |This endpoint uses intelligent two-tier caching to optimize performance:
-// |
-// |**Stable Data Cache (Long TTL):**
-// |- Metrics older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600")} seconds (${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} minutes) are considered immutable/stable
-// |- These are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400")} seconds (${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours)
-// |- Used when your query's from_date is older than the stable boundary
-// |
-// |**Recent Data Cache (Short TTL):**
-// |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds
-// |- Used when your query includes recent data or has no from_date
-// |
-// |**STRONGLY RECOMMENDED: Always specify from_date in your queries!**
-// |
-// |**Why from_date matters:**
-// |- Queries WITH from_date older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} mins → cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours (fast!)
-// |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds (slower)
-// |
-// |**Examples:**
-// |- `from_date=2025-01-01T00:00:00.000Z` → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours cache (historical data)
-// |- `from_date=$DateWithMsExampleString` (recent date) → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds cache (recent data)
-// |- No from_date (e.g., `?limit=50`) → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds cache (assumes recent data)
-// |
-// |For best performance on historical/reporting queries, always include a from_date parameter!
-// |
-// |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics
-// |
-// |You can filter by the following fields by applying url parameters
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
-// |
-// |1 from_date e.g.:from_date=$DateWithMsExampleString Defaults to the Unix Epoch i.e. ${theEpochTime}
-// | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!
-// |
-// |2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}
-// |
-// |3 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |4 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |5 sort_by (defaults to date field) eg: sort_by=date
-// | possible values:
-// | "url",
-// | "date",
-// | "username" (or "user_name" for backward compatibility),
-// | "app_name",
-// | "developer_email",
-// | "implemented_by_partial_function",
-// | "implemented_in_version",
-// | "consumer_id",
-// | "verb",
-// | "http_status_code"
-// |
-// |6 direction (defaults to date desc) eg: direction=desc
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78
-// |
-// |Other filters:
-// |
-// |7 consumer_id (if null ignore)
-// |
-// |8 user_id (if null ignore)
-// |
-// |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |10 url (if null ignore), note: can not contain '&'.
-// |
-// |11 app_name (if null ignore)
-// |
-// |12 implemented_by_partial_function (if null ignore),
-// |
-// |13 implemented_in_version (if null ignore)
-// |
-// |14 verb (if null ignore)
-// |
-// |15 correlation_id (if null ignore)
-// |
-// |16 duration (if null ignore) - Returns calls where duration > specified value (in milliseconds). Use this to find slow API calls. eg: duration=5000 returns calls taking more than 5 seconds
-// |
-// |17 http_status_code (if null ignore) - Returns calls with specific HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors
-// |
-// """.stripMargin,
-// EmptyBody,
-// metricsJsonV510,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canReadMetrics)))
-//
-// lazy val getMetrics: OBPEndpoint = {
-// case "management" :: "metrics" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// metrics <- Future(APIMetrics.apiMetrics.vend.getAllMetrics(obpQueryParams))
-// } yield {
-// (JSONFactory510.createMetricsJson(metrics), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersForUserIdsOnly,
-// implementedInApiVersion,
-// nameOf(getCustomersForUserIdsOnly),
-// "GET",
-// "/users/current/customers/customer_ids",
-// "Get Customers for Current User (IDs only)",
-// s"""Gets all Customers Ids that are linked to a User.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customersWithAttributesJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser)
-// )
-//
-// lazy val getCustomersForUserIdsOnly : OBPEndpoint = {
-// case "users" :: "current" :: "customers" :: "customer_ids" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (customers, callContext) <- Connector.connector.vend.getCustomersByUserId(cc.userId, cc.callContext) map {
-// connectorEmptyResponse(_, cc.callContext)
-// }
-// } yield {
-// (JSONFactory510.createCustomersIds(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getCustomersByLegalName,
-// implementedInApiVersion,
-// nameOf(getCustomersByLegalName),
-// "POST",
-// "/banks/BANK_ID/customers/legal-name",
-// "Get Customers by Legal Name",
-// s"""Gets the Customers specified by Legal Name.
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerLegalNameJsonV510,
-// customerJsonV310,
-// List(
-// AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersByLegalName: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "legal-name" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomersAtOneBank, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerLegalNameJsonV510 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerLegalNameJsonV510]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomersByCustomerLegalName(bank.bankId, postedData.legal_name, callContext)
-// } yield {
-// (JSONFactory300.createCustomersJson(customer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createAtm,
-// implementedInApiVersion,
-// nameOf(createAtm),
-// "POST",
-// "/banks/BANK_ID/atms",
-// "Create ATM",
-// s"""Create ATM.""",
-// postAtmJsonV510,
-// atmJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canCreateAtm, canCreateAtmAtAnyBank))
-// )
-// lazy val createAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// atmJsonV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV510]}", 400, cc.callContext) {
-// val atm = json.extract[PostAtmJsonV510]
-// //Make sure the Create contains proper ATM ID
-// atm.id.get
-// atm
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", 400, cc.callContext) {
-// atmJsonV510.bank_id == bankId.value
-// }
-// atm <- NewStyle.function.tryons(CouldNotTransformJsonToInternalModel + " Atm", 400, cc.callContext) {
-// JSONFactory510.transformToAtmFromV510(atmJsonV510)
-// }
-// (atm, callContext) <- NewStyle.function.createOrUpdateAtm(atm, cc.callContext)
-// (atmAttributes, callContext) <- NewStyle.function.getAtmAttributesByAtm(bankId, atm.atmId, callContext)
-// } yield {
-// (JSONFactory510.createAtmJsonV510(atm, atmAttributes), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAtm,
-// implementedInApiVersion,
-// nameOf(updateAtm),
-// "PUT",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "UPDATE ATM",
-// s"""Update ATM.""",
-// atmJsonV510.copy(id = None, attributes = None),
-// atmJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canUpdateAtm, canUpdateAtmAtAnyBank))
-// )
-// lazy val updateAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (atm, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// atmJsonV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV510]}", 400, callContext) {
-// json.extract[AtmJsonV510]
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", 400, callContext) {
-// atmJsonV510.bank_id == bankId.value
-// }
-// atm <- NewStyle.function.tryons(CouldNotTransformJsonToInternalModel + " Atm", 400, callContext) {
-// JSONFactory510.transformToAtmFromV510(atmJsonV510.copy(id = Some(atmId.value)))
-// }
-// (atm, callContext) <- NewStyle.function.createOrUpdateAtm(atm, callContext)
-// (atmAttributes, callContext) <- NewStyle.function.getAtmAttributesByAtm(bankId, atm.atmId, callContext)
-// } yield {
-// (JSONFactory510.createAtmJsonV510(atm, atmAttributes), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAtms,
-// implementedInApiVersion,
-// nameOf(getAtms),
-// "GET",
-// "/banks/BANK_ID/atms",
-// "Get Bank ATMS",
-// s"""Returns information about ATMs for a single bank specified by BANK_ID including:
-// |
-// |* Address
-// |* Geo Location
-// |* License the data under this endpoint is released under
-// |
-// |Pagination:
-// |
-// |By default, 100 records are returned.
-// |
-// |You can use the url query parameters *limit* and *offset* for pagination
-// |
-// |${userAuthenticationMessage(!getAtmsIsPublic)}""".stripMargin,
-// EmptyBody,
-// atmsJsonV510,
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagATM)
-// )
-// lazy val getAtms: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val limit = ObpS.param("limit")
-// val offset = ObpS.param("offset")
-// for {
-// (_, callContext) <- getAtmsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"${InvalidNumber} limit:${limit.getOrElse("")}", cc = callContext) {
-// limit match {
-// case Full(i) => i.toList.forall(c => Character.isDigit(c) == true)
-// case _ => true
-// }
-// }
-// _ <- Helper.booleanToFuture(failMsg = maximumLimitExceeded, cc = callContext) {
-// limit match {
-// case Full(i) if i.toInt > 10000 => false
-// case _ => true
-// }
-// }
-// (atms, callContext) <- NewStyle.function.getAtmsByBankId(bankId, offset, limit, callContext)
-//
-// atmAndAttributesTupleList: List[(AtmT, List[AtmAttribute])] <- Future.sequence(atms.map(
-// atm => NewStyle.function.getAtmAttributesByAtm(bankId, atm.atmId, callContext).map(_._1).map(
-// attributes =>{
-// (atm-> attributes)
-// }
-// )))
-//
-// } yield {
-// (JSONFactory510.createAtmsJsonV510(atmAndAttributesTupleList), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getAtm,
-// implementedInApiVersion,
-// nameOf(getAtm),
-// "GET",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "Get Bank ATM",
-// s"""Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:
-// |
-// |* Address
-// |* Geo Location
-// |* License the data under this endpoint is released under
-// |* ATM Attributes
-// |
-// |
-// |
-// |${userAuthenticationMessage(!getAtmsIsPublic)}""".stripMargin,
-// EmptyBody,
-// atmJsonV510,
-// List(AuthenticatedUserIsRequired, BankNotFound, AtmNotFoundByAtmId, UnknownError),
-// List(apiTagATM)
-// )
-// lazy val getAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getAtmsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (atm, callContext) <- NewStyle.function.getAtm(bankId, atmId, callContext)
-// (atmAttributes, callContext) <- NewStyle.function.getAtmAttributesByAtm(bankId, atmId, callContext)
-// } yield {
-// (JSONFactory510.createAtmJsonV510(atm, atmAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAtm,
-// implementedInApiVersion,
-// nameOf(deleteAtm),
-// "DELETE",
-// "/banks/BANK_ID/atms/ATM_ID",
-// "Delete ATM",
-// s"""Delete ATM.
-// |
-// |This will also delete all its attributes.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagATM),
-// Some(List(canDeleteAtmAtAnyBank, canDeleteAtm))
-// )
-// lazy val deleteAtm: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "atms" :: AtmId(atmId) :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (atm, callContext) <- NewStyle.function.getAtm(bankId, atmId, cc.callContext)
-// (deleted, callContext) <- NewStyle.function.deleteAtm(atm, callContext)
-// (atmAttributes, callContext) <- NewStyle.function.deleteAtmAttributesByAtmId(atmId, callContext)
-// } yield {
-// (Full(deleted && atmAttributes), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createConsumerDynamicRegistration,
-// implementedInApiVersion,
-// nameOf(createConsumerDynamicRegistration),
-// "POST",
-// "/dynamic-registration/consumers",
-// "Create a Consumer(Dynamic Registration)",
-// s"""Create a Consumer with full certificate validation (mTLS access) - **Recommended for PSD2/Berlin Group compliance**.
-// |
-// |This endpoint provides **secure, validated consumer registration** unlike the standard `/management/consumers` endpoint.
-// |
-// |**How it works (for comprehension flow):**
-// |
-// |1. **Extract JWT from request**: Parse the signed JWT from the request body
-// |2. **Extract certificate**: Get certificate from `PSD2-CERT` header in PEM format
-// |3. **Verify JWT signature**: Validate JWT is signed with the certificate's private key (proves possession)
-// |4. **Parse JWT payload**: Extract consumer details (description, app_name, app_type, developer_email, redirect_url)
-// |5. **Extract certificate info**: Parse certificate to get Common Name, Email, Organization
-// |6. **Validate against Regulated Entity**: Check certificate exists in Regulated Entity registry (PSD2 requirement)
-// |7. **Create consumer**: Generate credentials and create consumer record with validated certificate
-// |8. **Return consumer with certificate info**: Returns consumer details including parsed certificate information
-// |
-// |**Certificate Validation (CRITICAL SECURITY DIFFERENCE from regular creation):**
-// |
-// |[YES] **JWT Signature Verification**: JWT must be signed with certificate's private key - proves TPP owns the certificate
-// |[YES] **Regulated Entity Check**: Certificate must match a pre-registered Regulated Entity in the database
-// |[YES] **Certificate Binding**: Certificate is permanently bound to the consumer at creation time
-// |[YES] **CA Validation**: Certificate chain can be validated against trusted root CAs during API requests
-// |[YES] **PSD2 Compliance**: Meets EU regulatory requirements for TPP registration
-// |
-// |**Security benefits vs regular consumer creation:**
-// |
-// || Feature | Regular Creation | Dynamic Registration |
-// ||---------|-----------------|---------------------|
-// || Certificate validation | [NO] None | [YES] Full validation |
-// || Regulated Entity check | [NO] Not required | [YES] Required |
-// || JWT signature proof | [NO] Not required | [YES] Required (proves private key possession) |
-// || Self-signed certs | [YES] Accepted | [NO] Rejected |
-// || PSD2 compliant | [NO] No | [YES] Yes |
-// || Rogue TPP prevention | [NO] No | [YES] Yes |
-// |
-// |**Prerequisites:**
-// |1. TPP must be registered as a Regulated Entity with their certificate
-// |2. Certificate must be provided in `PSD2-CERT` request header (PEM format)
-// |3. JWT must be signed with the private key corresponding to the certificate
-// |4. Trust store must be configured with trusted root CAs
-// |
-// |**JWT Payload Structure:**
-// |
-// |Minimal:
-// |```json
-// |{ "description":"TPP Application Description" }
-// |```
-// |
-// |Full:
-// |```json
-// |{
-// | "description": "Payment Initiation Service",
-// | "app_name": "Tesobe GmbH",
-// | "app_type": "Confidential",
-// | "developer_email": "contact@tesobe.com",
-// | "redirect_url": "https://tpp.example.com/callback"
-// |}
-// |```
-// |
-// |**Note:** JWT must be signed with the private key that corresponds to the public key in the certificate sent via `PSD2-CERT` header.
-// |
-// |**Certificate Information Extraction:**
-// |
-// |The endpoint automatically extracts information from the certificate:
-// |- Common Name (CN) → used as app_name if not provided in JWT
-// |- Email Address → used as developer_email if not provided
-// |- Organization (O) → used as company
-// |- Certificate validity period
-// |- Issuer information
-// |
-// |**Configuration Required:**
-// |- `truststore.path.tpp_signature` - Path to trust store for CA validation
-// |- `truststore.password.tpp_signature` - Trust store password
-// |- Regulated Entity must be pre-registered with certificate public key
-// |
-// |**Error Scenarios:**
-// |- JWT signature invalid → `PostJsonIsNotSigned` (400)
-// |- Certificate not in Regulated Entity registry → `RegulatedEntityNotFoundByCertificate` (400)
-// |- Invalid JWT format → `InvalidJsonFormat` (400)
-// |- Missing PSD2-CERT header → Signature verification fails
-// |
-// |**This is the SECURE way to register consumers for production PSD2/Berlin Group implementations.**
-// |
-// |""",
-// ConsumerJwtPostJsonV510("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXNjcmlwdGlvbiI6IlRQUCBkZXNjcmlwdGlvbiJ9.c5gPPsyUmnVW774y7h2xyLXg0wdtu25nbU2AvOmyzcWa7JTdCKuuy3CblxueGwqYkQDDQIya1Qny4blyAvh_a1Q28LgzEKBcH7Em9FZXerhkvR9v4FWbCC5AgNLdQ7sR8-rUQdShmJcGDKdVmsZjuO4XhY2Zx0nFnkcvYfsU9bccoAvkKpVJATXzwBqdoEOuFlplnbxsMH1wWbAd3hbcPPWTdvO43xavNZTB5ybgrXVDEYjw8D-98_ZkqxS0vfvhJ4cGefHViaFzp6zXm7msdBpcE__O9rFbdl9Gvup_bsMbrHJioIrmc2d15Yc-tTNTF9J4qjD_lNxMRlx5o2TZEw"),
-// consumerJsonV510,
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDirectory, apiTagConsumer),
-// Some(Nil))
-//
-//
-// lazy val createConsumerDynamicRegistration: OBPEndpoint = {
-// case "dynamic-registration" :: "consumers" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedJwt <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
-// json.extract[ConsumerJwtPostJsonV510]
-// }
-// pem = APIUtil.`getPSD2-CERT`(cc.requestHeaders)
-// _ <- Helper.booleanToFuture(PostJsonIsNotSigned, 400, cc.callContext) {
-// verifyJwt(postedJwt.jwt, pem.getOrElse(""))
-// }
-// postedJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
-// parse(getSignedPayloadAsJson(postedJwt.jwt).getOrElse("{}")).extract[ConsumerPostJsonV510]
-// }
-// certificateInfo: CertificateInfoJsonV510 <- Future(X509.getCertificateInfo(pem)) map {
-// unboxFullOrFail(_, cc.callContext, X509GeneralError)
-// }
-// _ <- Helper.booleanToFuture(RegulatedEntityNotFoundByCertificate, 400, cc.callContext) {
-// MappedRegulatedEntityProvider.getRegulatedEntities()
-// .exists(_.entityCertificatePublicKey.replace("""\n""", "") == pem.getOrElse("").replace("""\n""", ""))
-// }
-// (consumer, callContext) <- createConsumerNewStyle(
-// key = Some(Helpers.randomString(40).toLowerCase),
-// secret = Some(Helpers.randomString(40).toLowerCase),
-// isActive = Some(true),
-// name = getCommonName(pem).or(postedJson.app_name) ,
-// appType = postedJson.app_type.map(AppType.valueOf).orElse(Some(AppType.valueOf("Confidential"))),
-// description = Some(postedJson.description),
-// developerEmail = getEmailAddress(pem).or(postedJson.developer_email),
-// company = getOrganization(pem),
-// redirectURL = postedJson.redirect_url,
-// createdByUserId = None,
-// clientCertificate = pem,
-// logoURL = None,
-// cc.callContext
-// )
-// } yield {
-// // Format the data as json
-// val json = JSONFactory510.createConsumerJSON(consumer, Some(certificateInfo))
-// // Return
-// (json, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// private def consumerDisabledText() = {
-// if(APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) == false) {
-// "Please note: Your consumer may be disabled as a result of this action."
-// } else {
-// ""
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createConsumer,
-// implementedInApiVersion,
-// nameOf(createConsumer),
-// "POST",
-// "/management/consumers",
-// "Create a Consumer",
-// s"""Create a Consumer (Authenticated access).
-// |
-// |A Consumer represents an application that uses the Open Bank Project API. Each Consumer has:
-// |- A unique **key** (40 character random string) - used as the client ID for authentication
-// |- A unique **secret** (40 character random string) - used for secure authentication
-// |- An **app_type** (Confidential or Public) - determines OAuth2 flow requirements
-// |- Metadata like app_name, description, developer_email, company, etc.
-// |
-// |**How it works (for comprehension flow):**
-// |
-// |1. **Extract authenticated user**: Retrieves the currently logged-in user who is creating the consumer
-// |2. **Parse and validate JSON request**: Extracts the CreateConsumerRequestJsonV510 from the request body
-// |3. **Determine app_type**: Converts the string "Confidential" or "Public" to the AppType enum
-// |4. **Generate credentials**: Creates random 40-character key and secret for the new consumer
-// |5. **Create consumer record**: Calls createConsumerNewStyle with all parameters:
-// | - Auto-generated key and secret
-// | - enabled flag (controls if consumer is active)
-// | - app_name, description, developer_email, company
-// | - redirect_url (for OAuth flows)
-// | - client_certificate (optional, for certificate-based auth)
-// | - logo_url (optional)
-// | - createdByUserId (the authenticated user's ID)
-// |6. **Return response**: Returns the newly created consumer with HTTP 201 Created status
-// |
-// |**Client Certificate (Optional but Recommended for PSD2/Berlin Group):**
-// |
-// |The `client_certificate` field provides enhanced security through X.509 certificate validation.
-// |
-// |**IMPORTANT SECURITY NOTE:**
-// |- **This endpoint does NOT validate the certificate at creation time** - any certificate can be provided
-// |- The certificate is simply stored with the consumer record without checking if it's from a trusted CA
-// |- For PSD2/Berlin Group compliance with certificate validation, use the **Dynamic Registration** endpoint instead
-// |- Dynamic Registration validates certificates against registered Regulated Entities and trusted CAs
-// |
-// |**How certificates are used (after creation):**
-// |- Certificate is stored in PEM format (Base64-encoded X.509) with the consumer record
-// |- On subsequent API requests, the certificate from the `PSD2-CERT` header is compared against the stored certificate
-// |- If certificates don't match, access is denied even with valid OAuth2 tokens
-// |- First request populates the certificate if not set; subsequent requests must match that certificate
-// |
-// |**Certificate validation process (during API requests, NOT at consumer creation):**
-// |1. Certificate from `PSD2-CERT` header is compared to stored certificate (simple string match)
-// |2. Certificate is parsed from PEM format to X.509Certificate object
-// |3. Validated against a configured trust store (PKCS12 format) containing trusted root CAs
-// |4. Certificate chain is verified using PKIX validation
-// |5. Optional CRL (Certificate Revocation List) checking if enabled via `use_tpp_signature_revocation_list`
-// |6. Public key from certificate can verify signed requests (Berlin Group requirement)
-// |
-// |**Note:** Steps 3-6 only apply during API request validation, NOT during consumer creation via this endpoint.
-// |
-// |**Security benefits (when properly configured):**
-// |- **Certificate binding**: Links consumer to a specific certificate (prevents token reuse with different certs)
-// |- **Request verification**: Certificate's public key can verify signed requests
-// |- **Non-repudiation**: Certificate-based signatures prove request origin
-// |
-// |**Security limitations of this endpoint:**
-// |- **No validation at creation**: Any certificate (even self-signed or expired) can be stored
-// |- **No CA verification**: Certificate is not checked against trusted root CAs during creation
-// |- **No Regulated Entity check**: Does not verify the TPP is registered
-// |- **Use Dynamic Registration instead** for proper PSD2/Berlin Group compliance with full certificate validation
-// |
-// |**For proper PSD2 compliance:**
-// |Use the **Dynamic Consumer Registration** endpoint (`POST /obp/v5.1.0/dynamic-registration/consumers`) which:
-// |- Requires JWT-signed request using the certificate's private key
-// |- Validates certificate against Regulated Entity registry
-// |- Checks certificate is from a trusted CA using the configured trust store
-// |- Ensures proper QWAC/eIDAS compliance for EU TPPs
-// |
-// |**Configuration properties (for runtime validation):**
-// |- `truststore.path.tpp_signature` - Path to trust store for certificate validation during API requests
-// |- `truststore.password.tpp_signature` - Trust store password
-// |- `use_tpp_signature_revocation_list` - Enable/disable CRL checking during requests (default: true)
-// |- `consumer_validation_method_for_consent` - Set to "CONSUMER_CERTIFICATE" for cert-based validation
-// |- `bypass_tpp_signature_validation` - Emergency bypass (default: false, use only for testing)
-// |
-// |**Important**: The key and secret are only shown once in the response. Save them securely as they cannot be retrieved later.
-// |
-// |${consumerDisabledText()}
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// createConsumerRequestJsonV510,
-// consumerJsonOnlyForPostResponseV510,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canCreateConsumer)),
-// authMode = UserOrApplication
-// )
-//
-// lazy val createConsumer: OBPEndpoint = {
-// case "management" :: "consumers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (postedJson, appType)<- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// val createConsumerRequestJsonV510 = json.extract[CreateConsumerRequestJsonV510]
-// val appType = if(createConsumerRequestJsonV510.app_type.equals("Confidential")) AppType.valueOf("Confidential") else AppType.valueOf("Public")
-// (createConsumerRequestJsonV510,appType)
-// }
-// (consumer, callContext) <- createConsumerNewStyle(
-// key = Some(Helpers.randomString(40).toLowerCase),
-// secret = Some(Helpers.randomString(40).toLowerCase),
-// isActive = Some(postedJson.enabled),
-// name = Some(postedJson.app_name),
-// appType = Some(appType),
-// description = Some(postedJson.description),
-// developerEmail = Some(postedJson.developer_email),
-// company = Some(postedJson.company),
-// redirectURL = Some(postedJson.redirect_url),
-// createdByUserId = Some(u.userId),
-// clientCertificate = postedJson.client_certificate,
-// logoURL = postedJson.logo_url,
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createConsumerJsonOnlyForPostResponseV510(consumer, None), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createMyConsumer,
-// implementedInApiVersion,
-// nameOf(createMyConsumer),
-// "POST",
-// "/my/consumers",
-// "Create a Consumer",
-// s"""Create a Consumer (Authenticated access).
-// |
-// |""",
-// createConsumerRequestJsonV510,
-// consumerJsonV510,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagConsumer)
-// )
-//
-// lazy val createMyConsumer: OBPEndpoint = {
-// case "my" :: "consumers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (postedJson, appType)<- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// val createConsumerRequestJsonV510 = json.extract[CreateConsumerRequestJsonV510]
-// val appType = if(createConsumerRequestJsonV510.app_type.equals("Confidential")) AppType.valueOf("Confidential") else AppType.valueOf("Public")
-// (createConsumerRequestJsonV510,appType)
-// }
-// (consumer, callContext) <- createConsumerNewStyle(
-// key = Some(Helpers.randomString(40).toLowerCase),
-// secret = Some(Helpers.randomString(40).toLowerCase),
-// isActive = Some(postedJson.enabled),
-// name = Some(postedJson.app_name),
-// appType = Some(appType),
-// description = Some(postedJson.description),
-// developerEmail = Some(postedJson.developer_email),
-// company = Some(postedJson.company),
-// redirectURL = Some(postedJson.redirect_url),
-// createdByUserId = Some(u.userId),
-// clientCertificate = postedJson.client_certificate,
-// logoURL = postedJson.logo_url,
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createConsumerJsonOnlyForPostResponseV510(consumer, None), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCallsLimit,
-// implementedInApiVersion,
-// nameOf(getCallsLimit),
-// "GET",
-// "/management/consumers/CONSUMER_ID/consumer/rate-limits",
-// "Get Rate Limits for a Consumer",
-// s"""
-// |Get Calls limits per Consumer.
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// callLimitsJson510Example,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canReadCallLimits)))
-//
-//
-// lazy val getCallsLimit: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "rate-limits" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, cc.callContext)
-// rateLimiting <- RateLimitingDI.rateLimiting.vend.getAllByConsumerId(consumerId, None)
-// } yield {
-// (createCallLimitJson(rateLimiting), HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsumerRedirectURL,
-// implementedInApiVersion,
-// nameOf(updateConsumerRedirectURL),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/redirect_url",
-// "Update Consumer RedirectURL",
-// s"""Update an existing redirectUrl for a Consumer specified by CONSUMER_ID.
-// |
-// | ${consumerDisabledText()}
-// |
-// | CONSUMER_ID can be obtained after you register the application.
-// |
-// | Or use the endpoint 'Get Consumers' to get it
-// |
-// """.stripMargin,
-// consumerRedirectUrlJSON,
-// consumerJSON,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateConsumerRedirectUrl))
-// )
-//
-// lazy val updateConsumerRedirectURL: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "redirect_url" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) match {
-// case true => Future(Full(Unit))
-// case false => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUpdateConsumerRedirectUrl, callContext)
-// }
-// postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// json.extract[ConsumerRedirectUrlJSON]
-// }
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// //only the developer that created the Consumer should be able to edit it
-// _ <- Helper.booleanToFuture(UserNoPermissionUpdateConsumer, 400, callContext) {
-// consumer.createdByUserId.equals(u.userId)
-// }
-// //update the redirectURL and isactive (set to false when change redirectUrl) field in consumer table
-// updatedConsumer <- NewStyle.function.updateConsumer(
-// id = consumer.id.get,
-// isActive = Some(APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", defaultValue = false)),
-// redirectURL = Some(postJson.redirect_url),
-// callContext = callContext
-// )
-// } yield {
-// val json = JSONFactory510.createConsumerJSON(updatedConsumer)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsumerLogoURL,
-// implementedInApiVersion,
-// nameOf(updateConsumerLogoURL),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/logo_url",
-// "Update Consumer LogoURL",
-// s"""Update an existing logoURL for a Consumer specified by CONSUMER_ID.
-// |
-// | ${consumerDisabledText()}
-// |
-// | CONSUMER_ID can be obtained after you register the application.
-// |
-// | Or use the endpoint 'Get Consumers' to get it
-// |
-// """.stripMargin,
-// consumerLogoUrlJson,
-// consumerJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateConsumerLogoUrl))
-// )
-//
-// lazy val updateConsumerLogoURL: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "logo_url" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// json.extract[ConsumerLogoUrlJson]
-// }
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// updatedConsumer <- NewStyle.function.updateConsumer(
-// id = consumer.id.get,
-// logoURL = Some(postJson.logo_url),
-// callContext = callContext
-// )
-// } yield {
-// (JSONFactory510.createConsumerJSON(updatedConsumer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// staticResourceDocs += ResourceDoc(
-// updateConsumerCertificate,
-// implementedInApiVersion,
-// nameOf(updateConsumerCertificate),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/certificate",
-// "Update Consumer Certificate",
-// s"""Update a Certificate for a Consumer specified by CONSUMER_ID.
-// |
-// | ${consumerDisabledText()}
-// |
-// | CONSUMER_ID can be obtained after you register the application.
-// |
-// | Or use the endpoint 'Get Consumers' to get it
-// |
-// """.stripMargin,
-// consumerCertificateJson,
-// consumerJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateConsumerCertificate))
-// )
-//
-// lazy val updateConsumerCertificate: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "certificate" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// json.extract[ConsumerCertificateJson]
-// }
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// updatedConsumer <- NewStyle.function.updateConsumer(
-// id = consumer.id.get,
-// certificate = Some(postJson.certificate),
-// callContext = callContext
-// )
-// } yield {
-// (JSONFactory510.createConsumerJSON(updatedConsumer), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateConsumerName,
-// implementedInApiVersion,
-// nameOf(updateConsumerName),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/name",
-// "Update Consumer Name",
-// s"""Update an existing name for a Consumer specified by CONSUMER_ID.
-// |
-// | ${consumerDisabledText()}
-// |
-// | CONSUMER_ID can be obtained after you register the application.
-// |
-// | Or use the endpoint 'Get Consumers' to get it
-// |
-// """.stripMargin,
-// consumerNameJson,
-// consumerJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canUpdateConsumerName))
-// )
-//
-// lazy val updateConsumerName: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "name" :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
-// json.extract[ConsumerNameJson]
-// }
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, cc.callContext)
-// updatedConsumer <- NewStyle.function.updateConsumer(
-// id = consumer.id.get,
-// name = Some(postJson.app_name),
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory510.createConsumerJSON(updatedConsumer), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getConsumer,
-// implementedInApiVersion,
-// nameOf(getConsumer),
-// "GET",
-// "/management/consumers/CONSUMER_ID",
-// "Get Consumer",
-// s"""Get the Consumer specified by CONSUMER_ID.
-// |
-// |""",
-// EmptyBody,
-// consumerJSON,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ConsumerNotFoundByConsumerId,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetConsumers)))
-//
-//
-// lazy val getConsumer: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, cc.callContext)
-// user <- Users.users.vend.getUserByUserIdFuture(consumer.createdByUserId.get)
-// } yield {
-// (createConsumerJSON(consumer, user), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// getConsumers,
-// implementedInApiVersion,
-// nameOf(getConsumers),
-// "GET",
-// "/management/consumers",
-// "Get Consumers",
-// s"""Get the all Consumers.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |${urlParametersDocument(true, true)}
-// |
-// |""",
-// EmptyBody,
-// consumersJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetConsumers)),
-// authMode = UserOrApplication
-// )
-//
-//
-// lazy val getConsumers: OBPEndpoint = {
-// case "management" :: "consumers" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// _ = logger.info(s"========== CONSUMER QUERY DEBUG START ==========")
-// _ = logger.info(s"[CONSUMER-QUERY] Full URL: ${cc.url}")
-// _ = logger.info(s"[CONSUMER-QUERY] HTTP Params: $httpParams")
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, Some(cc))
-// _ = logger.info(s"[CONSUMER-QUERY] OBP Query Params: $obpQueryParams")
-// _ = obpQueryParams.foreach(param => logger.info(s"[CONSUMER-QUERY] - Param: $param"))
-// totalCount <- Future(Consumer.count())
-// _ = logger.info(s"[CONSUMER-QUERY] Total consumers in database: $totalCount")
-// allConsumers <- Future(Consumer.findAll())
-// consumersWithNullDate = allConsumers.filter(c => c.createdAt.get == null)
-// _ = logger.info(s"[CONSUMER-QUERY] Consumers with NULL createdAt: ${consumersWithNullDate.length}")
-// _ = if (consumersWithNullDate.nonEmpty) {
-// consumersWithNullDate.foreach(c => logger.info(s"[CONSUMER-QUERY] - NULL createdAt: Consumer ID: ${c.id.get}, Name: ${c.name.get}"))
-// }
-// consumers <- Consumers.consumers.vend.getConsumersFuture(obpQueryParams, callContext)
-// _ = logger.info(s"[CONSUMER-QUERY] Consumers returned from query: ${consumers.length}")
-// _ = consumers.foreach(c => logger.info(s"[CONSUMER-QUERY] - Consumer ID: ${c.id.get}, Name: ${c.name.get}, CreatedAt: ${c.createdAt.get}"))
-// _ = logger.info(s"[CONSUMER-QUERY] RESULT: Returned ${consumers.length} out of $totalCount total consumers")
-// _ = logger.info(s"========== CONSUMER QUERY DEBUG END ==========")
-// } yield {
-// (JSONFactory510.createConsumersJson(consumers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// grantUserAccessToViewById,
-// implementedInApiVersion,
-// nameOf(grantUserAccessToViewById),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/grant",
-// "Grant User access to View",
-// s"""Grants the User identified by USER_ID access to the view on a bank account identified by VIEW_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |**Permission Requirements:**
-// |The requesting user must have access to the source VIEW_ID and must possess specific grant permissions:
-// |
-// |**For System Views (e.g., owner, accountant, auditor, public etc.):**
-// |- The user's current view must have the target view listed in its `canGrantAccessToViews` field
-// |- Example: If granting access to "accountant" view, the user's view must include "accountant" in `canGrantAccessToViews`
-// |
-// |**For Custom Views (account-specific views):**
-// |- The user's current view must have the `can_grant_access_to_custom_views` permission in its `allowed_actions` field
-// |- This permission allows granting access to any custom view on the account
-// |
-// |**Security Checks Performed:**
-// |1. User authentication validation
-// |2. JSON format validation (USER_ID and VIEW_ID required)
-// |3. Permission authorization via `APIUtil.canGrantAccessToView()`
-// |4. Target user existence verification
-// |5. Target view existence and type validation (system vs custom)
-// |6. Final access grant operation in database
-// |
-// |**Final Database Operation:**
-// |The system creates an `AccountAccess` record linking the user to the view if one doesn't already exist.
-// |This operation includes:
-// |- Duplicate check: Prevents creating duplicate access records (idempotent operation)
-// |- Public view restriction: Blocks access to public views if disabled instance-wide
-// |- Database constraint validation: Ensures referential integrity
-// |
-// |**Note:** The permission model ensures users can only delegate access rights they themselves possess or are explicitly authorized to grant.
-// |
-// |""",
-// postAccountAccessJsonV510,
-// viewJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,
-// UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,
-// InvalidJsonFormat,
-// UserNotFoundById,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotGrantAccountAccess,
-// UnknownError
-// ),
-// List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired))
-//
-// lazy val grantUserAccessToViewById: OBPEndpoint = {
-// //add access for specific user to a specific system view
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) ::"views":: ViewId(viewId):: "account-access" :: "grant" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV510 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostAccountAccessJsonV510]
-// }
-// targetViewId = ViewId(postJson.view_id)
-// msg = getUserLacksGrantPermissionErrorMessage(viewId, targetViewId)
-// _ <- Helper.booleanToFuture(msg, 403, cc = cc.callContext) {
-// APIUtil.canGrantAccessToView(BankIdAccountIdViewId(bankId,accountId,viewId),targetViewId, u, callContext)
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, callContext)
-// view <- isValidSystemViewId(targetViewId.value) match {
-// case true => ViewNewStyle.systemView(targetViewId, callContext)
-// case false => ViewNewStyle.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// }
-// addedView <- JSONFactory400.grantAccountAccessToUser(bankId, accountId, user, view, callContext)
-//
-// } yield {
-// val viewJson = JSONFactory300.createViewJSON(addedView)
-// (viewJson, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// revokeUserAccessToViewById,
-// implementedInApiVersion,
-// nameOf(revokeUserAccessToViewById),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/revoke",
-// "Revoke User access to View",
-// s"""Revoke the User identified by USER_ID access to the view identified.
-// |
-// |${userAuthenticationMessage(true)}.
-// |
-// |""",
-// postAccountAccessJsonV510,
-// revokedJsonV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount,
-// UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount,
-// InvalidJsonFormat,
-// UserNotFoundById,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotRevokeAccountAccess,
-// CannotFindAccountAccess,
-// UnknownError
-// ),
-// List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired))
-//
-// lazy val revokeUserAccessToViewById: OBPEndpoint = {
-// //add access for specific user to a specific system view
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" ::ViewId(viewId) :: "account-access" :: "revoke" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostAccountAccessJsonV510]
-// }
-// targetViewId = ViewId(postJson.view_id)
-//
-// msg = getUserLacksRevokePermissionErrorMessage(viewId, targetViewId)
-//
-// _ <- Helper.booleanToFuture(msg, 403, cc = cc.callContext) {
-// APIUtil.canRevokeAccessToView(BankIdAccountIdViewId(bankId, accountId, viewId),targetViewId, u, callContext)
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, cc.callContext)
-// view <- isValidSystemViewId(targetViewId.value) match {
-// case true => ViewNewStyle.systemView(targetViewId, callContext)
-// case false => ViewNewStyle.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// }
-// revoked <- isValidSystemViewId(targetViewId.value) match {
-// case true => ViewNewStyle.revokeAccessToSystemView(bankId, accountId, view, user, callContext)
-// case false => ViewNewStyle.revokeAccessToCustomView(view, user, callContext)
-// }
-// } yield {
-// (RevokedJsonV400(revoked), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUserWithAccountAccessById,
-// implementedInApiVersion,
-// nameOf(createUserWithAccountAccessById),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/user-account-access",
-// "Create (DAuth) User with Account Access",
-// s"""This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain.
-// |
-// |Put the smart contract address in username
-// |
-// |For provider use "dauth"
-// |
-// |This endpoint will create the (DAuth) User with username and provider if the User does not already exist.
-// |
-// |${userAuthenticationMessage(true)} and the logged in user needs to be account holder.
-// |
-// |For information about DAuth see below:
-// |
-// |${Glossary.getGlossaryItem("DAuth")}
-// |
-// |""",
-// postCreateUserAccountAccessJsonV400,
-// List(viewJsonV300),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,
-// UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,
-// InvalidJsonFormat,
-// SystemViewNotFound,
-// ViewNotFound,
-// CannotGrantAccountAccess,
-// UnknownError
-// ),
-// List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired, apiTagDAuth))
-//
-// lazy val createUserWithAccountAccessById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" ::ViewId(viewId) :: "user-account-access" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostCreateUserAccountAccessJsonV510 "
-// for {
-// (Full(u), callContext) <- SS.user
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostCreateUserAccountAccessJsonV510]
-// }
-// //provider must start with dauth., can not create other provider users.
-// _ <- Helper.booleanToFuture(s"$InvalidUserProvider The user.provider must be start with 'dauth.'", cc = Some(cc)) {
-// postJson.provider.startsWith("dauth.")
-// }
-// targetViewId = ViewId(postJson.view_id)
-// msg = getUserLacksGrantPermissionErrorMessage(viewId, targetViewId)
-//
-// _ <- Helper.booleanToFuture(msg, 403, cc = Some(cc)) {
-// APIUtil.canGrantAccessToView(BankIdAccountIdViewId(bankId, accountId, viewId) ,targetViewId, u, callContext)
-// }
-// (targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postJson.provider, postJson.username, cc.callContext)
-// view <- isValidSystemViewId(targetViewId.value) match {
-// case true => ViewNewStyle.systemView(targetViewId, callContext)
-// case false => ViewNewStyle.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// }
-// addedView <- isValidSystemViewId(targetViewId.value) match {
-// case true => ViewNewStyle.grantAccessToSystemView(bankId, accountId, view, targetUser, callContext)
-// case false => ViewNewStyle.grantAccessToCustomView(view, targetUser, callContext)
-// }
-// } yield {
-// val viewsJson = JSONFactory300.createViewJSON(addedView)
-// (viewsJson, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionRequestById,
-// implementedInApiVersion,
-// nameOf(getTransactionRequestById),
-// "GET",
-// "/management/transaction-requests/TRANSACTION_REQUEST_ID",
-// "Get Transaction Request by ID.",
-// """Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID.
-// |
-// """.stripMargin,
-// EmptyBody,
-// transactionRequestWithChargeJSON210,
-// List(
-// $AuthenticatedUserIsRequired,
-// GetTransactionRequestsException,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2),
-// Some(List(canGetTransactionRequestAtOneBank, canGetTransactionRequestAtAnyBank))
-// )
-//
-// lazy val getTransactionRequestById: OBPEndpoint = {
-// case "management" :: "transaction-requests" :: TransactionRequestId(requestId) :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (transactionRequest, callContext) <- NewStyle.function.getTransactionRequestImpl(requestId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(transactionRequest.from.bank_id, u.userId, canGetTransactionRequestAtOneBank :: canGetTransactionRequestAtAnyBank :: Nil, callContext)
-// } yield {
-// val json = JSONFactory210.createTransactionRequestWithChargeJSON(transactionRequest)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// resourceDocs += ResourceDoc(
-// getTransactionRequests,
-// implementedInApiVersion,
-// nameOf(getTransactionRequests),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests",
-// "Get Transaction Requests." ,
-// """Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.
-// |
-// |The VIEW_ID specified must be 'owner' and the user must have access to this view.
-// |
-// |Version 2.0.0 now returns charge information.
-// |
-// |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:
-// |
-// |* Transaction Request Id
-// |* Type
-// |* Status (INITIATED, COMPLETED)
-// |* Challenge (in order to confirm the request)
-// |* From Bank / Account
-// |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)
-// |* Related Transactions
-// |
-// |PSD2 Context: PSD2 requires transparency of charges to the customer.
-// |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.
-// |The customer can proceed with the Transaction by answering the security challenge.
-// |
-// |We support query transaction request by attribute
-// |URL params example:/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests?invoiceNumber=123&referenceNumber=456
-// |
-// """.stripMargin,
-// EmptyBody,
-// transactionRequestWithChargeJSONs210,
-// List(
-// AuthenticatedUserIsRequired,
-// BankNotFound,
-// BankAccountNotFound,
-// UserNoPermissionAccessView,
-// ViewDoesNotPermitAccess,
-// GetTransactionRequestsException,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS))
-//
-// lazy val getTransactionRequests: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-requests" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.isEnabledTransactionRequests(callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkAccountAccessAndGetView(viewId, BankIdAccountId(bankId, accountId), Full(u), callContext)
-// _ <- Helper.booleanToFuture(
-// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})",
-// cc=callContext){
-// view.allowed_actions.exists(_ ==CAN_SEE_TRANSACTION_REQUESTS)
-// }
-// (transactionRequests, callContext) <- Future(Connector.connector.vend.getTransactionRequests210(u, fromAccount, callContext)) map {
-// unboxFullOrFail(_, callContext, GetTransactionRequestsException)
-// }
-// (transactionRequestAttributes, callContext) <- NewStyle.function.getByAttributeNameValues(bankId, req.params, true, callContext)
-// transactionRequestIds = transactionRequestAttributes.map(_.transactionRequestId)
-//
-// transactionRequestsFiltered = if(req.params.isEmpty)
-// transactionRequests
-// else
-// transactionRequests.filter(transactionRequest => transactionRequestIds.contains(transactionRequest.id))
-//
-// } yield {
-// val json = JSONFactory510.createTransactionRequestJSONs(transactionRequestsFiltered, transactionRequestAttributes)
-//
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateTransactionRequestStatus,
-// implementedInApiVersion,
-// nameOf(updateTransactionRequestStatus),
-// "PUT",
-// "/management/transaction-requests/TRANSACTION_REQUEST_ID",
-// "Update Transaction Request Status",
-// s""" Update Transaction Request Status
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PostTransactionRequestStatusJsonV510(TransactionRequestStatus.COMPLETED.toString),
-// PostTransactionRequestStatusJsonV510(TransactionRequestStatus.COMPLETED.toString),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest),
-// Some(List(canUpdateTransactionRequestStatusAtOneBank, canUpdateTransactionRequestStatusAtAnyBank))
-// )
-//
-// lazy val updateTransactionRequestStatus : OBPEndpoint = {
-// case "management" :: "transaction-requests" :: TransactionRequestId(transactionRequestId) :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostTransactionRequestStatusJsonV510"
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostTransactionRequestStatusJsonV510]
-// }
-// (existingTransactionRequest, callContext) <- NewStyle.function.getTransactionRequestImpl(transactionRequestId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(existingTransactionRequest.from.bank_id, u.userId, canUpdateTransactionRequestStatusAtOneBank :: canUpdateTransactionRequestStatusAtAnyBank :: Nil, callContext)
-// _ <- NewStyle.function.saveTransactionRequestStatusImpl(transactionRequestId, postedData.status, callContext)
-// (transactionRequest, callContext) <- NewStyle.function.getTransactionRequestImpl(transactionRequestId, callContext)
-// } yield {
-// (TransactionRequestStatusJsonV510(transactionRequest.id.value, transactionRequest.status), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountAccessByUserId,
-// implementedInApiVersion,
-// nameOf(getAccountAccessByUserId),
-// "GET",
-// "/users/USER_ID/account-access",
-// "Get Account Access by USER_ID",
-// s"""Get Account Access by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// accountsMinimalJson400,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canSeeAccountAccessForAnyUser)))
-//
-// lazy val getAccountAccessByUserId : OBPEndpoint = {
-// case "users" :: userId :: "account-access" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
-// (_, accountAccess) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
-// } yield {
-// (JSONFactory400.createAccountsMinimalJson400(accountAccess), HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getApiTags,
-// implementedInApiVersion,
-// nameOf(getApiTags),
-// "GET",
-// "/tags",
-// "Get API Tags",
-// s"""Get API TagsGet API Tags
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |""",
-// EmptyBody,
-// accountsMinimalJson400,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi))
-//
-// lazy val getApiTags : OBPEndpoint = {
-// case "tags" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future.successful(()) // Just start async call
-// } yield {
-// (APITags(ApiTag.allDisplayTagNames.toList), HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCoreAccountByIdThroughView,
-// implementedInApiVersion,
-// nameOf(getCoreAccountByIdThroughView),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID",
-// "Get Account by Id (Core) through the VIEW_ID",
-// s"""Information returned about the account through VIEW_ID :
-// |""".stripMargin,
-// EmptyBody,
-// moderatedCoreAccountJsonV400,
-// List($AuthenticatedUserIsRequired, $BankAccountNotFound,UnknownError),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-// lazy val getCoreAccountByIdThroughView : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @Full(u), account, callContext) <- SS.userAccount
-// bankIdAccountId = BankIdAccountId(account.bankId, account.accountId)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId , bankIdAccountId, user, callContext)
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(account, view, user, callContext)
-// } yield {
-// val availableViews: List[View] = Views.views.vend.privateViewsUserCanAccessForAccount(u, BankIdAccountId(account.bankId, account.accountId))
-// (createNewCoreBankAccountJson(moderatedAccount, availableViews), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountBalances,
-// implementedInApiVersion,
-// nameOf(getBankAccountBalances),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/balances",
-// "Get Account Balances by BANK_ID and ACCOUNT_ID through the VIEW_ID",
-// """Get the Balances for the Account specified by BANK_ID and ACCOUNT_ID through the VIEW_ID.""",
-// EmptyBody,
-// accountBalanceV400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UserNoPermissionAccessView,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountBalances : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "balances" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// bankIdAccountId = BankIdAccountId(bankId, accountId)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, bankIdAccountId, Full(u), callContext)
-// // Note we do one explicit check here rather than use moderated account because this provides an explicit message
-// failMsg = ViewDoesNotPermitAccess + s" You need the `${(CAN_SEE_BANK_ACCOUNT_BALANCE)}` permission on VIEW_ID(${viewId.value})"
-// _ <- Helper.booleanToFuture(failMsg, 403, cc = callContext) {
-// view.allowed_actions.exists(_ ==CAN_SEE_BANK_ACCOUNT_BALANCE)
-// }
-// (accountBalances, callContext) <- BalanceNewStyle.getBankAccountBalances(bankIdAccountId, callContext)
-// } yield {
-// (createAccountBalancesJson(accountBalances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountsBalances,
-// implementedInApiVersion,
-// nameOf(getBankAccountsBalances),
-// "GET",
-// "/banks/BANK_ID/balances",
-// "Get Account Balances by BANK_ID",
-// """Get the Balances for the Account specified by BANK_ID.""",
-// EmptyBody,
-// accountBalancesV400Json,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountsBalances : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (allowedAccounts, callContext) <- BalanceNewStyle.getAccountAccessAtBank(u, bankId, callContext)
-// (accountsBalances, callContext) <- BalanceNewStyle.getBankAccountsBalances(allowedAccounts, callContext)
-// } yield {
-// (createBalancesJson(accountsBalances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountsBalancesThroughView,
-// implementedInApiVersion,
-// nameOf(getBankAccountsBalancesThroughView),
-// "GET",
-// "/banks/BANK_ID/views/VIEW_ID/balances",
-// "Get Account Balances by BANK_ID through the VIEW_ID",
-// """Get the Balances for the Account specified by BANK_ID.""",
-// EmptyBody,
-// accountBalancesV400Json,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBankAccountsBalancesThroughView : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "views" :: ViewId(viewId) :: "balances" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (allowedAccounts, callContext) <- BalanceNewStyle.getAccountAccessAtBankThroughView(u, bankId, viewId, callContext)
-// (accountsBalances, callContext) <- BalanceNewStyle.getBankAccountsBalances(allowedAccounts, callContext)
-// } yield {
-// (createBalancesJson(accountsBalances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// lazy val counterPartyLimitIntro: String =
-// """Counter Party Limits can be used to restrict the Transaction Request amounts and frequencies (per month and year) that can be made to a Counterparty (Beneficiary).
-// |
-// |In order to implement VRP (Variable Recurring Payments) perform the following steps:
-// |1) Create a Custom View named e.g. VRP1.
-// |2) Place a Beneficiary Counterparty on that view.
-// |3) Add Counterparty Limits for that Counterparty.
-// |4) Generate a Consent containing the bank, account and view (e.g. VRP1)
-// |5) Let the App use the consent to trigger Transaction Requests.
-// |""".stripMargin
-//
-// staticResourceDocs += ResourceDoc(
-// createCounterpartyLimit,
-// implementedInApiVersion,
-// nameOf(createCounterpartyLimit),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits",
-// "Create Counterparty Limit",
-// s"""Create limits (for single or recurring payments) for a counterparty specified by the COUNTERPARTY_ID.
-// |
-// |Using this endpoint, we can attach a limit record to a Counterparty referenced by its counterparty_id (a UUID).
-// |
-// |For more information on Counterparty Limits, see ${Glossary.getGlossaryItemLink("Counterparty-Limits")}
-// |
-// |For an introduction to Counterparties in OBP, see ${Glossary.getGlossaryItemLink("Counterparties")}
-// |
-// |You can automate the process of creating counterparty limits and consents for VRP with this ${Glossary.getApiExplorerLink("endpoint", "OBPv5.1.0-createVRPConsentRequest")}.
-// |
-// |
-// |
-// |""".stripMargin,
-// postCounterpartyLimitV510,
-// counterpartyLimitV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// $CounterpartyNotFoundByCounterpartyId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCounterpartyLimits),
-// )
-// lazy val createCounterpartyLimit: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[PostCounterpartyLimitV510]}", 400, cc.callContext) {
-// json.extract[PostCounterpartyLimitV510]
-// }
-// _ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${postCounterpartyLimitV510.currency}'", cc=cc.callContext) {
-// isValidCurrencyISOCode(postCounterpartyLimitV510.currency)
-// }
-// (counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// cc.callContext
-// )
-// failMsg = s"$CounterpartyLimitAlreadyExists Current BANK_ID($bankId), ACCOUNT_ID($accountId), VIEW_ID($viewId),COUNTERPARTY_ID($counterpartyId)"
-// _ <- Helper.booleanToFuture(failMsg, cc = callContext) {
-// counterpartyLimitBox.isEmpty
-// }
-// (counterpartyLimit,callContext) <- NewStyle.function.createOrUpdateCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// postCounterpartyLimitV510.currency,
-// BigDecimal(postCounterpartyLimitV510.max_single_amount),
-// BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
-// postCounterpartyLimitV510.max_number_of_monthly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
-// postCounterpartyLimitV510.max_number_of_yearly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_total_amount),
-// postCounterpartyLimitV510.max_number_of_transactions,
-// cc.callContext
-// )
-// } yield {
-// (counterpartyLimit.toJValue, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateCounterpartyLimit,
-// implementedInApiVersion,
-// nameOf(updateCounterpartyLimit),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits",
-// "Update Counterparty Limit",
-// s"""Update Counterparty Limit.""",
-// postCounterpartyLimitV510,
-// counterpartyLimitV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// $CounterpartyNotFoundByCounterpartyId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCounterpartyLimits),
-// )
-// lazy val updateCounterpartyLimit: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[PostCounterpartyLimitV510]}", 400, cc.callContext) {
-// json.extract[PostCounterpartyLimitV510]
-// }
-// _ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${postCounterpartyLimitV510.currency}'", cc=cc.callContext) {
-// isValidCurrencyISOCode(postCounterpartyLimitV510.currency)
-// }
-// (counterpartyLimit,callContext) <- NewStyle.function.createOrUpdateCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// postCounterpartyLimitV510.currency,
-// BigDecimal(postCounterpartyLimitV510.max_single_amount),
-// BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
-// postCounterpartyLimitV510.max_number_of_monthly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
-// postCounterpartyLimitV510.max_number_of_yearly_transactions,
-// BigDecimal(postCounterpartyLimitV510.max_total_amount),
-// postCounterpartyLimitV510.max_number_of_transactions,
-// cc.callContext
-// )
-// } yield {
-// (counterpartyLimit.toJValue, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartyLimit,
-// implementedInApiVersion,
-// nameOf(getCounterpartyLimit),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits",
-// "Get Counterparty Limit",
-// s"""Get Counterparty Limit.""",
-// EmptyBody,
-// counterpartyLimitV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// $CounterpartyNotFoundByCounterpartyId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCounterpartyLimits),
-// )
-// lazy val getCounterpartyLimit: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (counterpartyLimit, callContext) <- NewStyle.function.getCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// cc.callContext
-// )
-// } yield {
-// (counterpartyLimit.toJValue, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartyLimitStatus,
-// implementedInApiVersion,
-// nameOf(getCounterpartyLimitStatus),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limit-status",
-// "Get Counterparty Limit Status",
-// s"""Get Counterparty Limit Status.""",
-// EmptyBody,
-// counterpartyLimitStatusV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// $CounterpartyNotFoundByCounterpartyId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCounterpartyLimits),
-// )
-// lazy val getCounterpartyLimitStatus: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limit-status" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (counterpartyLimit, callContext) <- NewStyle.function.getCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// cc.callContext
-// )
-// // Get the first day of the current month
-// firstDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth(1)
-//
-// // Get the last day of the current month
-// lastDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth(
-// LocalDate.now().lengthOfMonth()
-// )
-// // Get the first day of the current year
-// firstDayOfYear: LocalDate = LocalDate.now().withDayOfYear(1)
-//
-// // Get the last day of the current year
-// lastDayOfYear: LocalDate = LocalDate.now().withDayOfYear(
-// LocalDate.now().lengthOfYear()
-// )
-//
-// (fromBankAccount, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// // Convert LocalDate to Date
-// zoneId: ZoneId = ZoneId.systemDefault()
-// firstCurrentMonthDate: Date = Date.from(firstDayOfMonth.atStartOfDay(zoneId).toInstant)
-// // Adjust to include 23:59:59.999
-// lastCurrentMonthDate: Date = Date.from(
-// lastDayOfMonth
-// .atTime(23, 59, 59, 999000000)
-// .atZone(zoneId)
-// .toInstant
-// )
-//
-// firstCurrentYearDate: Date = Date.from(firstDayOfYear.atStartOfDay(zoneId).toInstant)
-// // Adjust to include 23:59:59.999
-// lastCurrentYearDate: Date = Date.from(
-// lastDayOfYear
-// .atTime(23, 59, 59, 999000000)
-// .atZone(zoneId)
-// .toInstant
-// )
-//
-// defaultFromDate: Date = theEpochTime
-// defaultToDate: Date = APIUtil.ToDateInFuture
-//
-// (sumOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// firstCurrentMonthDate: Date,
-// lastCurrentMonthDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// (countOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// firstCurrentMonthDate: Date,
-// lastCurrentMonthDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// (sumOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// firstCurrentYearDate: Date,
-// lastCurrentYearDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// (countOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// firstCurrentYearDate: Date,
-// lastCurrentYearDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// (sumOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// defaultFromDate: Date,
-// defaultToDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// (countOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
-// bankId,
-// accountId,
-// counterpartyId,
-// defaultFromDate: Date,
-// defaultToDate: Date,
-// callContext: Option[CallContext]
-// )
-//
-// } yield {
-// (CounterpartyLimitStatusV510(
-// counterparty_limit_id = counterpartyLimit.counterpartyLimitId: String,
-// bank_id = counterpartyLimit.bankId: String,
-// account_id = counterpartyLimit.accountId: String,
-// view_id = counterpartyLimit.viewId: String,
-// counterparty_id = counterpartyLimit.counterpartyId: String,
-// currency = counterpartyLimit.currency: String,
-// max_single_amount = counterpartyLimit.maxSingleAmount.toString(),
-// max_monthly_amount = counterpartyLimit.maxMonthlyAmount.toString(),
-// max_number_of_monthly_transactions = counterpartyLimit.maxNumberOfMonthlyTransactions: Int,
-// max_yearly_amount = counterpartyLimit.maxYearlyAmount.toString(),
-// max_number_of_yearly_transactions = counterpartyLimit.maxNumberOfYearlyTransactions: Int,
-// max_total_amount = counterpartyLimit.maxTotalAmount.toString(),
-// max_number_of_transactions = counterpartyLimit.maxNumberOfTransactions: Int,
-// status = CounterpartyLimitStatus(
-// currency_status = fromBankAccount.currency,
-// max_monthly_amount_status = sumOfTransactionsFromAccountToCounterpartyMonthly.amount,
-// max_number_of_monthly_transactions_status = countOfTransactionsFromAccountToCounterpartyMonthly,
-// max_yearly_amount_status = sumOfTransactionsFromAccountToCounterpartyYearly.amount,
-// max_number_of_yearly_transactions_status = countOfTransactionsFromAccountToCounterpartyYearly,
-// max_total_amount_status = sumOfAllTransactionsFromAccountToCounterparty.amount,
-// max_number_of_transactions_status = countOfAllTransactionsFromAccountToCounterparty
-// )
-// ), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCounterpartyLimit,
-// implementedInApiVersion,
-// nameOf(deleteCounterpartyLimit),
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits",
-// "Delete Counterparty Limit",
-// s"""Delete Counterparty Limit.""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// $CounterpartyNotFoundByCounterpartyId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagCounterpartyLimits),
-// )
-// lazy val deleteCounterpartyLimit: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (counterpartyLimit, callContext)<- NewStyle.function.deleteCounterpartyLimit(
-// bankId.value,
-// accountId.value,
-// viewId.value,
-// counterpartyId.value,
-// cc.callContext
-// )
-// } yield {
-// (Full(counterpartyLimit), HttpCode.`204`(cc.callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// createCustomView,
-// implementedInApiVersion,
-// nameOf(createCustomView),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views",
-// "Create Custom View",
-// s"""Create a custom view on bank account
-// |
-// | ${userAuthenticationMessage(true)} and the user needs to have access to the owner view.
-// | The 'alias' field in the JSON can take one of three values:
-// |
-// | * _public_: to use the public alias if there is one specified for the other account.
-// | * _private_: to use the private alias if there is one specified for the other account.
-// |
-// | * _''(empty string)_: to use no alias; the view shows the real name of the other account.
-// |
-// | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.
-// |
-// | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.
-// |
-// | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.
-// |
-// | You MUST use a leading _ (underscore) in the view name because other view names are reserved for OBP [system views](/index#group-View-System).
-// | """,
-// createCustomViewJson,
-// customViewJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount)
-// )
-// lazy val createCustomView: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"target-views" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, _, view, callContext) <- SS.userBankAccountView
-// createCustomViewJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[CreateViewJson]}", 400, cc.callContext) {
-// json.extract[CreateCustomViewJson]
-// }
-// //customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat + s"Current view_name (${createCustomViewJson.name})", cc = callContext) {
-// isValidCustomViewName(createCustomViewJson.name)
-// }
-//
-// permissionsFromSource = view.asInstanceOf[ViewDefinition].allowed_actions.toSet
-// permissionsFromTarget = createCustomViewJson.allowed_permissions
-//
-// _ <- Helper.booleanToFuture(failMsg = SourceViewHasLessPermission + s"Current source viewId($viewId) permissions ($permissionsFromSource), target viewName${createCustomViewJson.name} permissions ($permissionsFromTarget)", cc = callContext) {
-// permissionsFromTarget.toSet.subsetOf(permissionsFromSource)
-// }
-//
-// failMsg = s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_CREATE_CUSTOM_VIEW)}` permission on VIEW_ID(${viewId.value})"
-//
-// _ <- Helper.booleanToFuture(failMsg, cc = callContext) {
-// view.allowed_actions.exists(_ ==CAN_CREATE_CUSTOM_VIEW)
-// }
-// (view, callContext) <- ViewNewStyle.createCustomView(BankIdAccountId(bankId, accountId), createCustomViewJson.toCreateViewJson, callContext)
-// } yield {
-// (JSONFactory510.createViewJson(view), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// resourceDocs += ResourceDoc(
-// updateCustomView,
-// implementedInApiVersion,
-// nameOf(updateCustomView),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID",
-// "Update Custom View",
-// s"""Update an existing custom view on a bank account
-// |
-// |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.
-// |
-// |The json sent is the same as during view creation (above), with one difference: the 'name' field
-// |of a view is not editable (it is only set when a view is created)""",
-// updateCustomViewJson,
-// customViewJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount)
-// )
-// lazy val updateCustomView: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "target-views" :: ViewId(targetViewId) :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, _, view, callContext) <- SS.userBankAccountView
-// targetCreateCustomViewJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[UpdateCustomViewJson]}", 400, cc.callContext) {
-// json.extract[UpdateCustomViewJson]
-// }
-// //customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat + s"Current TARGET_VIEW_ID (${targetViewId})", cc = callContext) {
-// isValidCustomViewId(targetViewId.value)
-// }
-// permissionsFromSource = view.asInstanceOf[ViewDefinition].allowed_actions.toSet
-// permissionsFromTarget = targetCreateCustomViewJson.allowed_permissions
-//
-// _ <- Helper.booleanToFuture(failMsg = SourceViewHasLessPermission + s"Current source view permissions ($permissionsFromSource), target view permissions ($permissionsFromTarget)", cc = callContext) {
-// permissionsFromTarget.toSet.subsetOf(permissionsFromSource)
-// }
-//
-// failmsg = s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_UPDATE_CUSTOM_VIEW)}` permission on VIEW_ID(${viewId.value})"
-//
-// _ <- Helper.booleanToFuture(failmsg, cc = callContext) {
-// view.allowed_actions.exists(_ ==CAN_CREATE_CUSTOM_VIEW)
-// }
-//
-// (view, callContext) <- ViewNewStyle.updateCustomView(BankIdAccountId(bankId, accountId), targetViewId, targetCreateCustomViewJson.toUpdateViewJson, callContext)
-// } yield {
-// (JSONFactory510.createViewJson(view), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomView,
-// implementedInApiVersion,
-// nameOf(getCustomView),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID",
-// "Get Custom View",
-// s"""#Views
-// |
-// |
-// |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.
-// |
-// |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.
-// |
-// |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.
-// |
-// |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.
-// |
-// |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.
-// |
-// |**Metadata:**
-// |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.
-// |
-// |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).
-// |
-// |# All
-// |*Optional*
-// |
-// |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.
-// |
-// |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.""",
-// EmptyBody,
-// customViewJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount)
-// )
-// lazy val getCustomView: OBPEndpoint = {
-// //get the available views on an bank account
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "target-views" :: ViewId(targetViewId):: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, _, view, callContext) <- SS.userBankAccountView
-// //customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat + s"Current TARGET_VIEW_ID (${targetViewId.value})", cc = callContext) {
-// isValidCustomViewId(targetViewId.value)
-// }
-// failmsg = s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_GET_CUSTOM_VIEW)}`permission on any your views. Current VIEW_ID (${viewId.value})"
-// _ <- Helper.booleanToFuture(failmsg, cc = callContext) {
-// view.allowed_actions.exists(_ ==CAN_GET_CUSTOM_VIEW)
-// }
-// targetView <- ViewNewStyle.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// } yield {
-// (JSONFactory510.createViewJson(targetView), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomView,
-// implementedInApiVersion,
-// nameOf(deleteCustomView),
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID",
-// "Delete Custom View",
-// "Deletes the custom view specified by VIEW_ID on the bank account specified by ACCOUNT_ID at bank BANK_ID",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount)
-// )
-//
-// lazy val deleteCustomView: OBPEndpoint = {
-// //deletes a view on an bank account
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId ) :: "views" :: ViewId(viewId) :: "target-views" :: ViewId(targetViewId) :: Nil JsonDelete req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, _, view, callContext) <- SS.userBankAccountView
-// //customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat + s"Current TARGET_VIEW_ID (${targetViewId.value})", cc = callContext) {
-// isValidCustomViewId(targetViewId.value)
-// }
-// failMsg = s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_DELETE_CUSTOM_VIEW)}` permission on any your views.Current VIEW_ID (${viewId.value})"
-// _ <- Helper.booleanToFuture(failMsg, cc = callContext) {
-// view.allowed_actions.exists(_ ==CAN_DELETE_CUSTOM_VIEW)
-// }
-// _ <- ViewNewStyle.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// deleted <- ViewNewStyle.removeCustomView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createVRPConsentRequest,
-// implementedInApiVersion,
-// nameOf(createVRPConsentRequest),
-// "POST",
-// "/consumer/vrp-consent-requests",
-// "Create Consent Request VRP",
-// s"""
-// |This endpoint is used to begin the process of creating a consent that may be used for Variable Recurring Payments (VRPs).
-// |
-// |VRPs are useful in situations when a beneficiary needs to be paid different amounts on a regular basis.
-// |
-// |Once granted, the consent allows its holder to initiate multiple Transaction Requests to the Counterparty defined in this endpoint as long as the
-// |Counterparty Limits linked to this particular consent are respected.
-// |
-// |Client, Consumer or Application Authentication is mandatory for this endpoint.
-// |
-// |i.e. the caller of this endpoint is the API Client, Consumer or Application rather than a specific User.
-// |
-// |At the end of the process the following objects are created in OBP or connected backend systems:
-// | - An automatically generated View which controls access.
-// | - A Counterparty that is the Beneficiary of the Variable Recurring Payments. The Counterparty specifies the Bank Account number or other routing address.
-// | - Limits for the Counterparty which constrain the amount of money that can be sent to it in various periods (yearly, monthly, weekly).
-// |
-// |The Account holder may modify the Counterparty or Limits e.g. to increase or decrease the maximum possible payment amounts or the frequencey of the payments.
-// |
-// |
-// |In the case of a public client we use the client_id and private key to obtain an access token, otherwise we use the client_id and client_secret.
-// |The obtained access token is used in the HTTP Authorization header of the request as follows:
-// |
-// |Example:
-// |Authorization: Bearer eXtneO-THbQtn3zvK_kQtXXfvOZyZFdBCItlPDbR2Bk.dOWqtXCtFX-tqGTVR0YrIjvAolPIVg7GZ-jz83y6nA0
-// |
-// |After successfully creating the VRP consent request, you need to call the `Create Consent By CONSENT_REQUEST_ID` endpoint to finalize the consent using the CONSENT_REQUEST_ID returned by this endpoint.
-// |
-// |${applicationAccessMessage(true)}
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |
-// |""".stripMargin,
-// postVRPConsentRequestJsonV510,
-// vrpConsentRequestResponseJson,
-// List(
-// InvalidJsonFormat,
-// ConsentMaxTTL,
-// X509CannotGetCertificate,
-// X509GeneralError,
-// InvalidConnectorResponse,
-// UnknownError
-// ),
-// apiTagConsent :: apiTagVrp :: apiTagTransactionRequest :: Nil
-// )
-//
-// lazy val createVRPConsentRequest : OBPEndpoint = {
-// case "consumer" :: "vrp-consent-requests" :: Nil JsonPost postJson -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- applicationAccess(cc)
-// _ <- passesPsd2Aisp(callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostVRPConsentRequestJsonV510 "
-// postConsentRequestJsonV510: PostVRPConsentRequestJsonV510 <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// postJson.extract[PostVRPConsentRequestJsonV510]
-// }
-// maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty = "consents.max_time_to_live", defaultValue = 3600)
-// _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc = callContext) {
-// postConsentRequestJsonV510.time_to_live match {
-// case Some(ttl) => ttl <= maxTimeToLive
-// case _ => true
-// }
-// }
-// // we will first transfer AccountNumber or AccountNo to ACCOUNT_NUMBER, we will store ACCOUNT_NUMBER in the database.
-// fromAccountRoutingScheme = postConsentRequestJsonV510.from_account.account_routing.scheme
-// fromAccountRoutingSchemeOBPFormat = if(fromAccountRoutingScheme.equalsIgnoreCase("AccountNo")) "ACCOUNT_NUMBER" else StringHelpers.snakify(fromAccountRoutingScheme).toUpperCase
-// fromAccountRouting = postConsentRequestJsonV510.from_account.account_routing.copy(scheme =fromAccountRoutingSchemeOBPFormat)
-// fromAccountTweaked = postConsentRequestJsonV510.from_account.copy(account_routing = fromAccountRouting)
-//
-// toAccountRoutingScheme = postConsentRequestJsonV510.to_account.account_routing.scheme
-// toAccountRoutingSchemeOBPFormat = if(toAccountRoutingScheme.equalsIgnoreCase("AccountNo")) "ACCOUNT_NUMBER" else StringHelpers.snakify(toAccountRoutingScheme).toUpperCase
-// toAccountRouting = postConsentRequestJsonV510.to_account.account_routing.copy(scheme =toAccountRoutingSchemeOBPFormat)
-// toAccountTweaked = postConsentRequestJsonV510.to_account.copy(account_routing = toAccountRouting)
-//
-//
-//
-// fromBankAccountRoutings = BankAccountRoutings(
-// bank = BankRoutingJson(postConsentRequestJsonV510.from_account.bank_routing.scheme, postConsentRequestJsonV510.from_account.bank_routing.address),
-// account = BranchRoutingJsonV141(fromAccountRoutingSchemeOBPFormat, postConsentRequestJsonV510.from_account.account_routing.address),
-// branch = AccountRoutingJsonV121(postConsentRequestJsonV510.from_account.branch_routing.scheme, postConsentRequestJsonV510.from_account.branch_routing.address)
-// )
-//
-// // we need to add the consent_type internally, the user does not need to know it.
-// consentType = json.parse(s"""{"consent_type": "${ConsentType.VRP}"}""")
-//
-// (_, callContext) <- NewStyle.function.getBankAccountByRoutings(fromBankAccountRoutings, callContext)
-//
-// postConsentRequestJsonTweaked = postConsentRequestJsonV510.copy(
-// from_account = fromAccountTweaked,
-// to_account = toAccountTweaked
-// )
-// createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.createConsentRequest(
-// callContext.flatMap(_.consumer),
-// Some(compactRender(Extraction.decompose(postConsentRequestJsonTweaked) merge consentType))
-// )) map {
-// i => connectorEmptyResponse(i, callContext)
-// }
-// } yield {
-// (JSONFactory500.createConsentRequestResponseJson(createdConsentRequest), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createRegulatedEntityAttribute,
-// implementedInApiVersion,
-// nameOf(createRegulatedEntityAttribute),
-// "POST",
-// "/regulated-entities/REGULATED_ENTITY_ID/attributes",
-// "Create Regulated Entity Attribute",
-// s"""
-// | Create a new Regulated Entity Attribute for a given REGULATED_ENTITY_ID.
-// |
-// | The type field must be one of "STRING", "INTEGER", "DOUBLE" or "DATE_WITH_DAY".
-// | ${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// regulatedEntityAttributeRequestJsonV510,
-// regulatedEntityAttributeResponseJsonV510,
-// List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canCreateRegulatedEntityAttribute))
-// )
-//
-// lazy val createRegulatedEntityAttribute: OBPEndpoint = {
-// case "regulated-entities" :: entityId :: "attributes" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $RegulatedEntityAttributeRequestJsonV510 ", 400, cc.callContext) {
-// json.extract[RegulatedEntityAttributeRequestJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${RegulatedEntityAttributeType.DOUBLE}(12.1234), ${RegulatedEntityAttributeType.STRING}(TAX_NUMBER), ${RegulatedEntityAttributeType.INTEGER}(123) and ${RegulatedEntityAttributeType.DATE_WITH_DAY}(2012-04-23)"
-//
-// regulatedEntityAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// RegulatedEntityAttributeType.withName(postedData.attribute_type)
-// }
-//
-// (attribute, callContext) <- RegulatedEntityAttributeNewStyle.createOrUpdateRegulatedEntityAttribute(
-// regulatedEntityId = RegulatedEntityId(entityId),
-// regulatedEntityAttributeId = None,
-// name = postedData.name,
-// attributeType = regulatedEntityAttributeType,
-// value = postedData.value,
-// isActive = postedData.is_active,
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory510.createRegulatedEntityAttributeJson(attribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteRegulatedEntityAttribute,
-// implementedInApiVersion,
-// nameOf(deleteRegulatedEntityAttribute),
-// "DELETE",
-// "/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID",
-// "Delete Regulated Entity Attribute",
-// s"""
-// | Delete a Regulated Entity Attribute specified by REGULATED_ENTITY_ATTRIBUTE_ID.
-// |
-// | ${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canDeleteRegulatedEntityAttribute))
-// )
-//
-// lazy val deleteRegulatedEntityAttribute: OBPEndpoint = {
-// case "regulated-entities" :: entityId :: "attributes" :: attributeId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(entityId, cc.callContext)
-// (deleted, callContext) <- RegulatedEntityAttributeNewStyle.deleteRegulatedEntityAttribute(attributeId, cc.callContext)
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getRegulatedEntityAttributeById,
-// implementedInApiVersion,
-// nameOf(getRegulatedEntityAttributeById),
-// "GET",
-// "/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID",
-// "Get Regulated Entity Attribute By ID",
-// s"""
-// | Get a specific Regulated Entity Attribute by its REGULATED_ENTITY_ATTRIBUTE_ID.
-// |
-// | ${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// regulatedEntityAttributeResponseJsonV510,
-// List($AuthenticatedUserIsRequired,UnknownError),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canGetRegulatedEntityAttribute))
-// )
-//
-// lazy val getRegulatedEntityAttributeById: OBPEndpoint = {
-// case "regulated-entities" :: entityId :: "attributes" :: attributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(entityId, cc.callContext)
-// (attribute, callContext) <- RegulatedEntityAttributeNewStyle.getRegulatedEntityAttributeById(attributeId, cc.callContext)
-// } yield {
-// (JSONFactory510.createRegulatedEntityAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllRegulatedEntityAttributes,
-// implementedInApiVersion,
-// nameOf(getAllRegulatedEntityAttributes),
-// "GET",
-// "/regulated-entities/REGULATED_ENTITY_ID/attributes",
-// "Get All Regulated Entity Attributes",
-// s"""
-// | Get all attributes for the specified Regulated Entity.
-// |
-// | ${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// regulatedEntityAttributesJsonV510,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canGetRegulatedEntityAttributes))
-// )
-//
-// lazy val getAllRegulatedEntityAttributes: OBPEndpoint = {
-// case "regulated-entities" :: RegulatedEntityId(entityId) :: "attributes" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(entityId.value, cc.callContext)
-// (attributes, callContext) <- RegulatedEntityAttributeNewStyle.getRegulatedEntityAttributes(entityId, cc.callContext)
-// } yield {
-// (JSONFactory510.createRegulatedEntityAttributesJson(attributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateRegulatedEntityAttribute,
-// implementedInApiVersion,
-// nameOf(updateRegulatedEntityAttribute),
-// "PUT",
-// "/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID",
-// "Update Regulated Entity Attribute",
-// s"""
-// | Update an existing Regulated Entity Attribute specified by ATTRIBUTE_ID.
-// |
-// | ${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// regulatedEntityAttributeRequestJsonV510,
-// regulatedEntityAttributeResponseJsonV510,
-// List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError),
-// List(apiTagDirectory, apiTagApi),
-// Some(List(canUpdateRegulatedEntityAttribute))
-// )
-//
-// lazy val updateRegulatedEntityAttribute: OBPEndpoint = {
-// case "regulated-entities" :: entityId :: "attributes" :: attributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $RegulatedEntityAttributeRequestJsonV510 ", 400, cc.callContext) {
-// json.extract[RegulatedEntityAttributeRequestJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${RegulatedEntityAttributeType.DOUBLE}(12.1234), ${RegulatedEntityAttributeType.STRING}(TAX_NUMBER), ${RegulatedEntityAttributeType.INTEGER}(123) and ${RegulatedEntityAttributeType.DATE_WITH_DAY}(2012-04-23)"
-//
-// regulatedEntityAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// RegulatedEntityAttributeType.withName(postedData.attribute_type)
-// }
-// (entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(entityId, cc.callContext)
-// (updatedAttribute, callContext) <- RegulatedEntityAttributeNewStyle.createOrUpdateRegulatedEntityAttribute(
-// regulatedEntityId = RegulatedEntityId(entityId),
-// regulatedEntityAttributeId = Some(attributeId),
-// name = postedData.name,
-// attributeType = regulatedEntityAttributeType,
-// value = postedData.value,
-// isActive = postedData.is_active,
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory510.createRegulatedEntityAttributeJson(updatedAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankAccountBalance,
-// implementedInApiVersion,
-// nameOf(createBankAccountBalance),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances",
-// "Create Bank Account Balance",
-// s"""Create a new Balance for a Bank Account.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// bankAccountBalanceRequestJsonV510,
-// bankAccountBalanceResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagBalance),
-// Some(List(canCreateBankAccountBalance))
-// )
-//
-// lazy val createBankAccountBalance: OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "accounts" :: AccountId(accountId) :: "balances" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $BankAccountBalanceRequestJsonV510 ", 400, callContext) {
-// json.extract[BankAccountBalanceRequestJsonV510]
-// }
-// balanceAmount <- NewStyle.function.tryons(s"$InvalidNumber Current balance_amount is ${postedData.balance_amount}" , 400, cc.callContext) {
-// BigDecimal(postedData.balance_amount)
-// }
-// (balance, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.createOrUpdateBankAccountBalance(
-// bankId = bankId,
-// accountId = accountId,
-// balanceId = None,
-// balanceType = postedData.balance_type,
-// balanceAmount = balanceAmount,
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory510.createBankAccountBalanceJson(balance), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankAccountBalanceById,
-// implementedInApiVersion,
-// nameOf(getBankAccountBalanceById),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID",
-// "Get Bank Account Balance By ID",
-// s"""Get a specific Bank Account Balance by its BALANCE_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// bankAccountBalanceResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagBalance)
-// )
-//
-// lazy val getBankAccountBalanceById: OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "accounts" :: AccountId(accountId) :: "balances" :: BalanceId(balanceId) :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (balance, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountBalanceById(
-// balanceId,
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createBankAccountBalanceJson(balance), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllBankAccountBalances,
-// implementedInApiVersion,
-// nameOf(getAllBankAccountBalances),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances",
-// "Get All Bank Account Balances",
-// s"""Get all Balances for a Bank Account.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// bankAccountBalancesJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagBalance)
-// )
-//
-// lazy val getAllBankAccountBalances: OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "accounts" :: AccountId(accountId) :: "balances" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (balances, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountBalances(
-// accountId,
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createBankAccountBalancesJson(balances), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankAccountBalance,
-// implementedInApiVersion,
-// nameOf(updateBankAccountBalance),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID",
-// "Update Bank Account Balance",
-// s"""Update an existing Bank Account Balance specified by BALANCE_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// bankAccountBalanceRequestJsonV510,
-// bankAccountBalanceResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagBalance),
-// Some(List(canUpdateBankAccountBalance))
-// )
-//
-// lazy val updateBankAccountBalance: OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "accounts" :: AccountId(accountId) :: "balances" :: BalanceId(balanceId) :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the BankAccountBalanceRequestJsonV510 ", 400, callContext) {
-// json.extract[BankAccountBalanceRequestJsonV510]
-// }
-// balanceAmount <- NewStyle.function.tryons(s"$InvalidNumber Current balance_amount is ${postedData.balance_amount}" , 400, cc.callContext) {
-// BigDecimal(postedData.balance_amount)
-// }
-// (balance, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountBalanceById(
-// balanceId,
-// callContext
-// )
-// (balance, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.createOrUpdateBankAccountBalance(
-// bankId = bankId,
-// accountId = accountId,
-// balanceId = Some(balanceId),
-// balanceType = postedData.balance_type,
-// balanceAmount = balanceAmount,
-// callContext = callContext
-// )
-// } yield {
-// (JSONFactory510.createBankAccountBalanceJson(balance), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteBankAccountBalance,
-// implementedInApiVersion,
-// nameOf(deleteBankAccountBalance),
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID",
-// "Delete Bank Account Balance",
-// s"""Delete a Bank Account Balance specified by BALANCE_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagBalance),
-// Some(List(canDeleteBankAccountBalance))
-// )
-//
-// lazy val deleteBankAccountBalance: OBPEndpoint = {
-// case "banks" :: BankId(bankId):: "accounts" :: AccountId(accountId) :: "balances" :: BalanceId(balanceId) :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- SS.user
-// (balance, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountBalanceById(
-// balanceId,
-// callContext
-// )
-// (deleted, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.deleteBankAccountBalance(
-// balanceId,
-// callContext
-// )
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// getWebUiProps,
-// implementedInApiVersion,
-// nameOf(getWebUiProps),
-// "GET",
-// "/webui-props",
-// "Get WebUiProps",
-// s"""
-// |
-// |Get the all WebUiProps key values, those props key with "webui_" can be stored in DB, this endpoint get all from DB.
-// |
-// |url query parameter:
-// |active: It must be a boolean string. and If active = true, it will show
-// | combination of explicit (inserted) + implicit (default) method_routings.
-// |
-// |eg:
-// |${getObpApiRoot}/v5.1.0/webui-props
-// |${getObpApiRoot}/v5.1.0/webui-props?active=true
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "webui-props",
-// (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"))))
-// )
-// ,
-// List(
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagWebUiProps)
-// )
-// lazy val getWebUiProps: OBPEndpoint = {
-// case "webui-props":: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val active = ObpS.param("active").getOrElse("false")
-// for {
-// invalidMsg <- Future(s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """)
-// isActived <- NewStyle.function.tryons(invalidMsg, 400, cc.callContext) {
-// active.toBoolean
-// }
-// explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() }
-// implicitWebUiPropsRemovedDuplicated = if(isActived){
-// val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId= Some("default")))
-// if(explicitWebUiProps.nonEmpty){
-// //get the same name props in the `implicitWebUiProps`
-// val duplicatedProps : List[WebUiPropsCommons]= explicitWebUiProps.map(explicitWebUiProp => implicitWebUiProps.filter(_.name == explicitWebUiProp.name)).flatten
-// //remove the duplicated fields from `implicitWebUiProps`
-// implicitWebUiProps diff duplicatedProps
-// }
-// else implicitWebUiProps.distinct
-// } else {
-// List.empty[WebUiPropsCommons]
-// }
-// } yield {
-// val listCommons: List[WebUiPropsCommons] = explicitWebUiProps ++ implicitWebUiPropsRemovedDuplicated
-// (ListResult("webui_props", listCommons), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// addSystemViewPermission,
-// implementedInApiVersion,
-// nameOf(addSystemViewPermission),
-// "POST",
-// "/system-views/VIEW_ID/permissions",
-// "Add Permission to a System View",
-// """Add Permission to a System View.""",
-// createViewPermissionJson,
-// entitlementJSON,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// IncorrectRoleName,
-// EntitlementAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagSystemView),
-// Some(List(canCreateSystemViewPermission))
-// )
-//
-// lazy val addSystemViewPermission : OBPEndpoint = {
-// case "system-views" :: ViewId(viewId) :: "permissions" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// failMsg <- Future.successful(s"$InvalidJsonFormat The Json body should be the $CreateViewPermissionJson ")
-// createViewPermissionJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[CreateViewPermissionJson]
-// }
-// _ <- Helper.booleanToFuture(s"$InvalidViewPermissionName The current value is ${createViewPermissionJson.permission_name}", 400, cc.callContext) {
-// ALL_VIEW_PERMISSION_NAMES.exists( _ == createViewPermissionJson.permission_name)
-// }
-// _ <- ViewNewStyle.systemView(viewId, cc.callContext)
-// _ <- Helper.booleanToFuture(s"$ViewPermissionNameExists The current value is ${createViewPermissionJson.permission_name}", 400, cc.callContext) {
-// ViewPermission.findSystemViewPermission(viewId, createViewPermissionJson.permission_name).isEmpty
-// }
-// (viewPermission,callContext) <- ViewNewStyle.createSystemViewPermission(viewId, createViewPermissionJson.permission_name, createViewPermissionJson.extra_data, cc.callContext)
-// } yield {
-// (JSONFactory510.createViewPermissionJson(viewPermission), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// resourceDocs += ResourceDoc(
-// deleteSystemViewPermission,
-// implementedInApiVersion,
-// nameOf(deleteSystemViewPermission),
-// "DELETE",
-// "/system-views/VIEW_ID/permissions/PERMISSION_NAME",
-// "Delete Permission to a System View",
-// """Delete Permission to a System View
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError),
-// List(apiTagSystemView),
-// Some(List(canDeleteSystemViewPermission))
-// )
-// lazy val deleteSystemViewPermission: OBPEndpoint = {
-// case "system-views" :: ViewId(viewId) :: "permissions" :: permissionName :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (viewPermission, callContext) <- ViewNewStyle.findSystemViewPermission(viewId, permissionName, cc.callContext)
-// _ <- Helper.booleanToFuture(s"$DeleteViewPermissionError The current value is ${createViewPermissionJson.permission_name}", 400, cc.callContext) {
-// viewPermission.delete_!
-// }
-// } yield (true, HttpCode.`204`(cc.callContext))
-// }
-// }
-//
-//
-// }
-//}
-//
-//
-//
-//object APIMethods510 {
-// lazy val newStyleEndpoints: List[(String, String)] = Implementations5_1_0.resourceDocs.map {
-// rd => (rd.partialFunctionName, rd.implementedInApiVersion.toString())
-// }.toList
-//}
-//
\ No newline at end of file
diff --git a/obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala b/obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala
index fb10602e37..9ee118ea08 100644
--- a/obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala
+++ b/obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala
@@ -131,11 +131,11 @@ object Http4s510 {
val root: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `prefixPath` =>
EndpointHelpers.executeFuture(req) {
- Future.successful(JSONFactory510.getApiInfoJSON(OBPAPI5_1_0.version, OBPAPI5_1_0.versionStatus))
+ Future.successful(JSONFactory510.getApiInfoJSON(ApiVersion.v5_1_0, versionStatus))
}
case req @ GET -> `prefixPath` / "root" =>
EndpointHelpers.executeFuture(req) {
- Future.successful(JSONFactory510.getApiInfoJSON(OBPAPI5_1_0.version, OBPAPI5_1_0.versionStatus))
+ Future.successful(JSONFactory510.getApiInfoJSON(ApiVersion.v5_1_0, versionStatus))
}
}
diff --git a/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala b/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala
deleted file mode 100644
index 6f6dd2ec22..0000000000
--- a/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
-Open Bank Project - API
-Copyright (C) 2011-2019, TESOBE GmbH.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
-Email: contact@tesobe.com
-TESOBE GmbH.
-Osloer Strasse 16/17
-Berlin 13359, Germany
-
-This product includes software developed at
-TESOBE (http://www.tesobe.com/)
-
- */
-package code.api.v5_1_0
-
-import scala.language.reflectiveCalls
-import code.api.OBPRestHelper
-import code.api.util.VersionedOBPApis
-import code.api.v3_0_0.Http4s300
-import code.api.v3_1_0.{APIMethods310, Http4s310}
-import code.api.v4_0_0.{APIMethods400, Http4s400}
-import code.api.v5_0_0.{APIMethods500, OBPAPI5_0_0}
-import code.util.Helper.MdcLoggable
-import com.github.dwickern.macros.NameOf.nameOf
-import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
-
-/*
-This file defines which endpoints from all the versions are available in v5.1.0.
-All v5.1.0 endpoints have been migrated to Http4s510 — this object is retained
-only for resource-doc aggregation and the Lift dispatch registry.
- */
-object OBPAPI5_1_0 extends OBPRestHelper
- with APIMethods310
- with APIMethods400
- with APIMethods500
- with APIMethods510
- with MdcLoggable
- with VersionedOBPApis{
-
- val version : ApiVersion = ApiVersion.v5_1_0
-
- val versionStatus = ApiVersionStatus.BLEEDING_EDGE.toString
-
- // Re-export so tests that import OBPAPI5_1_0.Implementations5_1_0 still compile
- // after APIMethods510 was replaced with an empty stub.
- val Implementations5_1_0 = Http4s510.Implementations5_1_0
- // Re-export so nameOf references below (in excludeEndpoints) continue to compile
- // after APIMethods400 was replaced with an empty stub.
- val Implementations4_0_0 = Http4s400.Implementations4_0_0
- // Re-export so nameOf(Implementations3_1_0.xxx) in excludeEndpoints continues to compile
- // after APIMethods310 was replaced with an empty stub.
- val Implementations3_1_0 = Http4s310.Implementations3_1_0
- // Re-export so nameOf(Implementations3_0_0.xxx) in excludeEndpoints continues to compile
- // after APIMethods300 was replaced with an empty stub.
- val Implementations3_0_0 = Http4s300.Implementations3_0_0
-
- lazy val excludeEndpoints =
- nameOf(Implementations3_0_0.getUserByUsername) :: // following 4 endpoints miss Provider parameter in the URL, we introduce new ones in V510.
- nameOf(Implementations3_1_0.getBadLoginStatus) ::
- nameOf(Implementations3_1_0.unlockUser) ::
- nameOf(Implementations4_0_0.lockUser) ::
- nameOf(Implementations4_0_0.createUserWithAccountAccess) :: // following 3 endpoints miss ViewId parameter in the URL, we introduce new ones in V510.
- nameOf(Implementations4_0_0.grantUserAccessToView) ::
- nameOf(Implementations4_0_0.revokeUserAccessToView) ::
- nameOf(Implementations4_0_0.revokeGrantUserAccessToViews) ::// this endpoint is forbidden in V510, we do not support multi views in one endpoint from V510.
- Nil
-
- // All v5.1.0 endpoints live in Http4s510 — aggregate Http4s510.resourceDocs on top of v5.0.0.
- def allResourceDocs = collectResourceDocs(
- OBPAPI5_0_0.allResourceDocs,
- Http4s510.resourceDocs
- ).filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|")))
-
- // No Lift routes — all v5.1.0 endpoints are served by Http4s510.
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
- // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here.
-}
diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala
deleted file mode 100644
index 9dab4dfe61..0000000000
--- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala
+++ /dev/null
@@ -1,17183 +0,0 @@
-package code.api.v6_0_0
-
-/**
- * All v6.0.0 Lift endpoints have been migrated to Http4s600.
- * This stub is kept so that existing test files that import
- * APIMethods600.Implementations6_0_0 continue to compile.
- */
-object APIMethods600 {
- val Implementations6_0_0 = Http4s600.Implementations6_0_0
-}
-
-trait APIMethods600
-
-// ─── Original Lift implementation (commented out) ────────────────────────────
-//package code.api.v6_0_0
-//
-//import scala.language.reflectiveCalls
-//import code.accountattribute.AccountAttributeX
-//import code.api.Constant._
-//import code.api.{Constant, DirectLogin, JsonResponseException, ObpApiFailure}
-//import code.api.dynamic.endpoint.helper.CompiledObjects
-//import code.dynamicResourceDoc.JsonDynamicResourceDoc
-//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
-//import code.api.cache.{Caching, Redis, RedisMessaging}
-//import code.api.util.APIUtil._
-//import code.api.util.ApiRole
-//import code.api.util.ApiRole._
-//import code.api.util.ApiTag._
-//import code.api.util.ErrorMessages.{$AuthenticatedUserIsRequired, InvalidDateFormat, InvalidJsonFormat, UnknownError, DynamicEntityOperationNotAllowed, _}
-//import code.api.util.FutureUtil.EndpointContext
-//import code.api.util.{CertificateUtil, Glossary}
-//import code.api.util.JsonSchemaGenerator
-//import code.api.util.NewStyle.HttpCode
-//import code.api.util.{APIUtil, ApiVersionUtils, CallContext, DiagnosticDynamicEntityCheck, ErrorMessages, NewStyle, OBPLimit, OBPOffset, OBPSortBy, RateLimitingUtil}
-//import com.openbankproject.commons.util.json
-//import code.api.util.NewStyle.function.extractQueryParams
-//import code.api.util.newstyle.ViewNewStyle
-//import code.api.v3_0_0.JSONFactory300
-//import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
-//import code.api.v2_0_0.{BasicViewJson, JSONFactory200}
-//import code.api.v3_1_0.{JSONFactory310, PostCustomerNumberJsonV310}
-//import code.api.v1_2_1.{AccountHolderJSON, BankRoutingJsonV121, TransactionDetailsJSON}
-//import code.api.v4_0_0.{BankAttributeBankResponseJsonV400, CallLimitPostJsonV400}
-//import code.api.v4_0_0.JSONFactory400.createCallsLimitJson
-//import code.api.v5_0_0.JSONFactory500
-//import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500}
-//import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510}
-//import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
-//import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, ModeratedAccountJSON600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserWithViewAccessJsonV600, UsersWithViewAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createBankAccountJSON600, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600}
-//import code.metadata.tags.Tags
-//import code.products.ProductTagsProvider
-//import code.api.v6_0_0.OBPAPI6_0_0
-//import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider}
-//import code.mandate.{MappedMandateProvider}
-//import code.api.v6_0_0.JSONFactory600.{createMandateJsonV600, createMandatesJsonV600, createMandateProvisionJsonV600, createMandateProvisionsJsonV600, createSignatoryPanelJsonV600, createSignatoryPanelsJsonV600, createCounterpartyAttributeJson, createCounterpartyAttributesJson}
-//// Chat case classes are at package level in JSONFactory6.0.0.scala, not inside JSONFactory600 object
-//import code.metrics.{APIMetrics, ConnectorCountsRedis, ConnectorTraceProvider}
-//import code.bankconnectors.{Connector, LocalMappedConnectorInternal}
-//import code.bankconnectors.storedprocedure.StoredProcedureUtils
-//import code.bankconnectors.LocalMappedConnectorInternal._
-//import code.consumer.Consumers
-//import code.entitlement.Entitlement
-//import code.loginattempts.LoginAttempt
-//import code.model._
-//import code.users.{UserAgreement, UserAgreementProvider, Users}
-//import code.ratelimiting.RateLimitingDI
-//import code.util.Helper
-//import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN}
-//import code.views.Views
-//import code.views.system.{AccountAccess, ViewDefinition}
-//import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons, WebUiPropsPutJsonV600}
-//import code.dynamicEntity.{DynamicEntityCommons, DynamicEntityProvider, DynamicEntityT}
-//import code.DynamicData.{DynamicData, DynamicDataProvider}
-//import com.github.dwickern.macros.NameOf.nameOf
-//import com.openbankproject.commons.ExecutionContext.Implicits.global
-//import com.openbankproject.commons.dto.GetProductsParam
-//import com.openbankproject.commons.model._
-//import com.openbankproject.commons.model.enums.CounterpartyAttributeType
-//import com.openbankproject.commons.model.enums.DynamicEntityOperation._
-//import com.openbankproject.commons.model.enums.UserAttributeType
-//import code.api.util.newstyle.CounterpartyAttributeNewStyle
-//import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
-//import net.liftweb.common.{Box, Empty, Failure, Full}
-//import net.liftweb.util.Helpers.tryo
-//import org.apache.commons.lang3.StringUtils
-//import org.json4s.{Extraction, JsonParser}
-//import org.json4s.JsonAST.{JArray, JField, JNothing, JObject, JString, JValue}
-//import org.json4s.JsonDSL._
-//import net.liftweb.mapper.{By, Descending, MaxRows, NullRef, OrderBy}
-//import code.api.util.ExampleValue
-//import code.api.util.ExampleValue.dynamicEntityResponseBodyExample
-//import net.liftweb.common.Box
-//
-//import java.net.URLDecoder
-//import java.nio.charset.StandardCharsets
-//import java.text.SimpleDateFormat
-//import java.util.UUID.randomUUID
-//import scala.collection.immutable.{List, Nil}
-//import scala.collection.mutable.ArrayBuffer
-//import scala.concurrent.Future
-//import scala.concurrent.duration._
-//import scala.collection.JavaConverters._
-//import scala.util.Random
-//
-//
-//trait APIMethods600 {
-// self: RestHelper =>
-//
-// val Implementations6_0_0 = new Implementations600()
-//
-// class Implementations600 extends RestHelper with MdcLoggable {
-//
-// val implementedInApiVersion: ScannedApiVersion = ApiVersion.v6_0_0
-//
-// val staticResourceDocs = ArrayBuffer[ResourceDoc]()
-// val resourceDocs = staticResourceDocs
-//
-// val apiRelations = ArrayBuffer[ApiRelation]()
-// val codeContext = CodeContext(staticResourceDocs, apiRelations)
-//
-//
-// staticResourceDocs += ResourceDoc(
-// root,
-// implementedInApiVersion,
-// nameOf(root),
-// "GET",
-// "/root",
-// "Get API Info (root)",
-// """Returns information about:
-// |
-// |* API version
-// |* Hosted by information
-// |* Hosted at information
-// |* Energy source information
-// |* Git Commit""",
-// EmptyBody,
-// apiInfoJson400,
-// List(UnknownError, MandatoryPropertyIsNotSet),
-// apiTagApi :: Nil)
-//
-// lazy val root: OBPEndpoint = {
-// case (Nil | "root" :: Nil) JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(()) // Just start async call
-// } yield {
-// (JSONFactory510.getApiInfoJSON(OBPAPI6_0_0.version, OBPAPI6_0_0.versionStatus), HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getFeatures,
-// implementedInApiVersion,
-// nameOf(getFeatures),
-// "GET",
-// "/features",
-// "Get Features",
-// """Returns information about the features enabled on this OBP instance.
-// |
-// |No Authentication is Required.""",
-// EmptyBody,
-// featuresJsonV600,
-// List(UnknownError),
-// apiTagApi :: Nil)
-//
-// lazy val getFeatures: OBPEndpoint = {
-// case "features" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- Future(())
-// } yield {
-// val featuresJson = FeaturesJsonV600(
-// allow_public_views = APIUtil.getPropsAsBoolValue("allow_public_views", false),
-// allow_abac_account_access = APIUtil.getPropsAsBoolValue("allow_abac_account_access", false),
-// allow_account_firehose = APIUtil.getPropsAsBoolValue("allow_account_firehose", false),
-// allow_customer_firehose = APIUtil.getPropsAsBoolValue("allow_customer_firehose", false),
-// allow_direct_login = APIUtil.getPropsAsBoolValue("allow_direct_login", true),
-// allow_gateway_login = APIUtil.getPropsAsBoolValue("allow_gateway_login", false),
-// allow_oauth2_login = APIUtil.getPropsAsBoolValue("allow_oauth2_login", true),
-// allow_dauth = APIUtil.getPropsAsBoolValue("allow_dauth", false),
-// allow_sandbox_account_creation = APIUtil.getPropsAsBoolValue("allow_sandbox_account_creation", false),
-// allow_sandbox_data_import = APIUtil.getPropsAsBoolValue("allow_sandbox_data_import", false),
-// allow_account_deletion = APIUtil.getPropsAsBoolValue("allow_account_deletion", false),
-// allow_just_in_time_entitlements = APIUtil.getPropsAsBoolValue("create_just_in_time_entitlements", false)
-// )
-// (featuresJson, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestHold,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestHold),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/HOLD/transaction-requests",
-// "Create Transaction Request (HOLD)",
-// s"""
-// |
-// |Create a transaction request to move funds from the account to its Holding Account.
-// |If the Holding Account does not exist, it will be created automatically.
-// |
-// |${transactionRequestGeneralText}
-// |
-// """.stripMargin,
-// transactionRequestBodyHoldJsonV600,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestHold: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
-// "HOLD" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("HOLD")
-// LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
-// }
-//
-// // --- GET Holding Account by Parent ---
-// staticResourceDocs += ResourceDoc(
-// getHoldingAccountByReleaser,
-// implementedInApiVersion,
-// nameOf(getHoldingAccountByReleaser),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/holding-accounts",
-// "Get Holding Accounts By Releaser",
-// s"""
-// |
-// |Return the first Holding Account linked to the given releaser account via account attribute `RELEASER_ACCOUNT_ID`.
-// |Response is wrapped in a list and includes account attributes.
-// |
-// """.stripMargin,
-// EmptyBody,
-// moderatedCoreAccountsJsonV300,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// List(apiTagAccount)
-// )
-//
-// lazy val getHoldingAccountByReleaser: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "holding-accounts" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @Full(u), _, _, view, callContext) <- SS.userBankAccountView
-// // Find accounts by attribute RELEASER_ACCOUNT_ID
-// (accountIdsBox, callContext) <- AccountAttributeX.accountAttributeProvider.vend.getAccountIdsByParams(bankId, Map("RELEASER_ACCOUNT_ID" -> List(accountId.value))) map { ids => (ids, callContext) }
-// accountIds = accountIdsBox.getOrElse(Nil)
-// // load the first holding account
-// holdingOpt <- {
-// def firstHolding(ids: List[String]): Future[Option[BankAccount]] = ids match {
-// case Nil => Future.successful(None)
-// case id :: tail =>
-// NewStyle.function.getBankAccount(bankId, AccountId(id), callContext).flatMap { case (acc, cc) =>
-// if (acc.accountType == "HOLDING") Future.successful(Some(acc)) else firstHolding(tail)
-// }
-// }
-// firstHolding(accountIds)
-// }
-// holding <- NewStyle.function.tryons($BankAccountNotFound, 404, callContext) { holdingOpt.get }
-// moderatedAccount <- Future { holding.moderatedBankAccount(view, BankIdAccountId(holding.bankId, holding.accountId), user, callContext) } map {
-// x => unboxFullOrFail(x, callContext, UnknownError)
-// }
-// (attributes, callContext) <- NewStyle.function.getAccountAttributesByAccount(bankId, holding.accountId, callContext)
-// } yield {
-// val accountsJson = JSONFactory300.createFirehoseCoreBankAccountJSON(List(moderatedAccount), Some(attributes))
-// (accountsJson, HttpCode.`200`(callContext))
-// }
-// }
-//
-// // --- GET Accounts at Bank (v6.0.0 with account_id) ---
-// staticResourceDocs += ResourceDoc(
-// getAccountsAtBank,
-// implementedInApiVersion,
-// nameOf(getAccountsAtBank),
-// "GET",
-// "/banks/BANK_ID/accounts",
-// "Get Accounts at Bank",
-// s"""
-// |Returns the list of accounts at BANK_ID that the user has access to.
-// |For each account the API returns the account ID and the views available to the user.
-// |Each account must have at least one private View.
-// |
-// |This v6.0.0 version returns `account_id` instead of `id` for consistency with other v6.0.0 endpoints.
-// |
-// |Optional request parameters for filtering with attributes:
-// |URL params example: /banks/some-bank-id/accounts?limit=50&offset=1
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// """.stripMargin,
-// EmptyBody,
-// BasicAccountsJsonV600(List(BasicAccountJsonV600(
-// account_id = "8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// bank_id = "gh.29.uk",
-// label = "My Account",
-// views_available = List(BasicViewJson("owner", "Owner", false))
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagPrivateData, apiTagPublicData)
-// )
-//
-// lazy val getAccountsAtBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), bank, callContext) <- SS.userBank
-// (privateViewsUserCanAccessAtOneBank, privateAccountAccess) <- Future {
-// Views.views.vend.privateViewsUserCanAccessAtBank(u, bankId)
-// }
-// params <- Future {
-// req.params
-// .filterNot(_._1 == PARAM_TIMESTAMP)
-// .filterNot(_._1 == PARAM_LOCALE)
-// }
-// privateAccountAccess2 <-
-// if (params.isEmpty || privateAccountAccess.isEmpty) {
-// Future.successful(privateAccountAccess)
-// } else {
-// AccountAttributeX.accountAttributeProvider.vend
-// .getAccountIdsByParams(bankId, params)
-// .map { boxedAccountIds =>
-// val accountIds = boxedAccountIds.getOrElse(Nil)
-// privateAccountAccess.filter(aa =>
-// accountIds.contains(aa.account_id.get)
-// )
-// }
-// }
-// (availablePrivateAccounts, callContext2) <- bank.privateAccountsFuture(
-// privateAccountAccess2,
-// callContext
-// )
-// } yield {
-// val accountsJson = availablePrivateAccounts.map { account =>
-// val viewsAvailable = privateViewsUserCanAccessAtOneBank
-// .filter(v => v.bankId == bankId && v.accountId == account.accountId)
-// .map(v => BasicViewJson(v.viewId.value, v.name, v.isPublic))
-// JSONFactory600.createBasicAccountJsonV600(account, viewsAvailable)
-// }
-// (BasicAccountsJsonV600(accountsJson), HttpCode.`200`(callContext2))
-// }
-// }
-// }
-//
-// // --- GET Account by Id (Core) (v6.0.0 with account_id) ---
-// staticResourceDocs += ResourceDoc(
-// getCoreAccountByIdV600,
-// implementedInApiVersion,
-// nameOf(getCoreAccountByIdV600),
-// "GET",
-// "/my/banks/BANK_ID/accounts/ACCOUNT_ID/account",
-// "Get Account by Id (Core)",
-// s"""Information returned about the account specified by ACCOUNT_ID:
-// |
-// |* Number - The human readable account number given by the bank that identifies the account.
-// |* Label - A label given by the owner of the account
-// |* Owners - Users that own this account
-// |* Type - The type of account
-// |* Balance - Currency and Value
-// |* Account Routings - A list that might include IBAN or national account identifiers
-// |* Account Rules - A list that might include Overdraft and other bank specific rules
-// |* Tags - A list of Tags assigned to this account
-// |
-// |This call returns the owner view and requires access to that view.
-// |
-// |This v6.0.0 version returns `account_id` instead of `id` for consistency with other v6.0.0 endpoints.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ModeratedCoreAccountJsonV600(
-// account_id = "8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0",
-// bank_id = "gh.29.uk",
-// label = "My Account",
-// number = "123456",
-// product_code = "CURRENT",
-// balance = AmountOfMoneyJsonV121("EUR", "1000.00"),
-// account_routings = List(AccountRoutingJsonV121("IBAN", "DE89370400440532013000")),
-// views_basic = List("owner")
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankAccountNotFound,
-// UnknownError
-// ),
-// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getCoreAccountByIdV600: OBPEndpoint = {
-// case "my" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), account, callContext) <- SS.userAccount
-// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(
-// u,
-// BankIdAccountId(account.bankId, account.accountId),
-// callContext
-// )
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(
-// account,
-// view,
-// user,
-// callContext
-// )
-// } yield {
-// val availableViews: List[View] =
-// Views.views.vend.privateViewsUserCanAccessForAccount(
-// u,
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// (
-// JSONFactory600.createModeratedCoreAccountJsonV600(moderatedAccount, availableViews),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConsumerCallCounters,
-// implementedInApiVersion,
-// nameOf(getConsumerCallCounters),
-// "GET",
-// "/management/consumers/CONSUMER_ID/call-counters",
-// "Get Call Counts for Consumer",
-// s"""
-// |Get the call counters (current usage) for a specific consumer. Shows how many API calls have been made and when the counters reset.
-// |
-// |This endpoint returns the current state of API rate limits across all time periods (per second, per minute, per hour, per day, per week, per month).
-// |
-// |**Response Structure:**
-// |The response always contains a consistent structure with all six time periods, regardless of whether rate limits are configured or active.
-// |
-// |Each time period contains:
-// |- `calls_made`: Number of API calls made in the current period (null if no data available)
-// |- `reset_in_seconds`: Seconds until the counter resets (null if no data available)
-// |- `status`: Current state of the rate limit for this period
-// |
-// |**Status Values:**
-// |- `ACTIVE`: Rate limit counter is active and tracking calls. Both `calls_made` and `reset_in_seconds` will have numeric values.
-// |- `NO_COUNTER`: Key does not exist - the consumer has not made any API calls in this time period yet.
-// |- `EXPIRED`: The rate limit counter has expired (TTL reached 0). The counter will be recreated on the next API call.
-// |- `REDIS_UNAVAILABLE`: Cannot retrieve data from Redis. This indicates a system connectivity issue.
-// |- `DATA_MISSING`: Unexpected error - period data is missing from the response. This should not occur under normal circumstances.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// redisCallCountersJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetRateLimits)))
-//
-//
-// lazy val getConsumerCallCounters: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "call-counters" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, cc.callContext)
-// currentConsumerCallCounters <- Future(RateLimitingUtil.consumerRateLimitState(consumerId).toList)
-// } yield {
-// (createRedisCallCountersJson(currentConsumerCallCounters), HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createCallLimits,
-// implementedInApiVersion,
-// nameOf(createCallLimits),
-// "POST",
-// "/management/consumers/CONSUMER_ID/consumer/rate-limits",
-// "Create Rate Limits for a Consumer",
-// s"""
-// |Create Rate Limits for a Consumer
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// callLimitPostJsonV600,
-// callLimitJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canCreateRateLimits)))
-//
-//
-// lazy val createCallLimits: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "rate-limits" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateRateLimits, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CallLimitPostJsonV600 ", 400, callContext) {
-// json.extract[CallLimitPostJsonV600]
-// }
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// rateLimiting <- RateLimitingDI.rateLimiting.vend.createConsumerCallLimits(
-// consumerId,
-// postJson.from_date,
-// postJson.to_date,
-// postJson.api_version,
-// postJson.api_name,
-// postJson.bank_id,
-// Some(postJson.per_second_call_limit),
-// Some(postJson.per_minute_call_limit),
-// Some(postJson.per_hour_call_limit),
-// Some(postJson.per_day_call_limit),
-// Some(postJson.per_week_call_limit),
-// Some(postJson.per_month_call_limit)
-// )
-// } yield {
-// rateLimiting match {
-// case Full(rateLimitingObj) => (createCallLimitJsonV600(rateLimitingObj), HttpCode.`201`(callContext))
-// case _ => (UnknownError, HttpCode.`400`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// updateRateLimits,
-// implementedInApiVersion,
-// nameOf(updateRateLimits),
-// "PUT",
-// "/management/consumers/CONSUMER_ID/consumer/rate-limits/RATE_LIMITING_ID",
-// "Set Rate Limits / Call Limits per Consumer",
-// s"""
-// |Set the API rate limits / call limits for a Consumer:
-// |
-// |Rate limiting can be set:
-// |
-// |Per Second
-// |Per Minute
-// |Per Hour
-// |Per Week
-// |Per Month
-// |
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// callLimitPostJsonV400,
-// callLimitPostJsonV400,
-// List(
-// AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UpdateConsumerError,
-// UnknownError
-// ),
-// List(apiTagConsumer, apiTagRateLimits),
-// Some(List(canUpdateRateLimits)))
-//
-// lazy val updateRateLimits: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "rate-limits" :: rateLimitingId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.handleEntitlementsAndScopes("", u.userId, List(canUpdateRateLimits), callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CallLimitPostJsonV400 ", 400, callContext) {
-// json.extract[CallLimitPostJsonV400]
-// }
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// rateLimiting <- RateLimitingDI.rateLimiting.vend.updateConsumerCallLimits(
-// rateLimitingId,
-// postJson.from_date,
-// postJson.to_date,
-// postJson.api_version,
-// postJson.api_name,
-// postJson.bank_id,
-// Some(postJson.per_second_call_limit),
-// Some(postJson.per_minute_call_limit),
-// Some(postJson.per_hour_call_limit),
-// Some(postJson.per_day_call_limit),
-// Some(postJson.per_week_call_limit),
-// Some(postJson.per_month_call_limit)) map {
-// unboxFullOrFail(_, callContext, UpdateConsumerError)
-// }
-// } yield {
-// (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCallLimits,
-// implementedInApiVersion,
-// nameOf(deleteCallLimits),
-// "DELETE",
-// "/management/consumers/CONSUMER_ID/consumer/rate-limits/RATE_LIMITING_ID",
-// "Delete Rate Limit by Rate Limiting ID",
-// s"""
-// |Delete a specific Rate Limit by Rate Limiting ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canDeleteRateLimits)))
-//
-//
-// lazy val deleteCallLimits: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "consumer" :: "rate-limits" :: rateLimitingId :: Nil JsonDelete _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteRateLimits, callContext)
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// rateLimiting <- RateLimitingDI.rateLimiting.vend.getByRateLimitingId(rateLimitingId)
-// _ <- rateLimiting match {
-// case Full(rl) if rl.consumerId == consumerId =>
-// Future.successful(Full(rl))
-// case Full(_) =>
-// Future.successful(ObpApiFailure(s"Rate limiting ID $rateLimitingId does not belong to consumer $consumerId", 400, callContext))
-// case _ =>
-// Future.successful(ObpApiFailure(s"Rate limiting ID $rateLimitingId not found", 404, callContext))
-// }
-// deleteResult <- RateLimitingDI.rateLimiting.vend.deleteByRateLimitingId(rateLimitingId)
-// } yield {
-// deleteResult match {
-// case Full(true) => (EmptyBody, HttpCode.`204`(callContext))
-// case _ => (UnknownError, HttpCode.`400`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getActiveRateLimitsAtDate,
-// implementedInApiVersion,
-// nameOf(getActiveRateLimitsAtDate),
-// "GET",
-// "/management/consumers/CONSUMER_ID/active-rate-limits/DATE_WITH_HOUR",
-// "Get Active Rate Limits for Hour",
-// s"""
-// |Get the active rate limits for a consumer for a specific hour. Returns the aggregated rate limits from all active records during that hour.
-// |
-// |Rate limits are cached and queried at hour-level granularity.
-// |
-// |See ${Glossary.getGlossaryItemLink("Rate Limiting")} for more details on how rate limiting works.
-// |
-// |Date format: YYYY-MM-DD-HH in UTC timezone (e.g. 2025-12-31-13 for hour 13:00-13:59 UTC on Dec 31, 2025)
-// |
-// |Note: The hour is always interpreted in UTC for consistency across all servers.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// activeRateLimitsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// InvalidDateFormat,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetRateLimits)))
-//
-//
-// lazy val getActiveRateLimitsAtDate: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "active-rate-limits" :: dateWithHourString :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetRateLimits, callContext)
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// date <- NewStyle.function.tryons(s"$InvalidDateFormat Current date format is: $dateWithHourString. Please use this format: YYYY-MM-DD-HH in UTC (e.g. 2025-12-31-13 for hour 13:00-13:59 UTC on Dec 31, 2025)", 400, callContext) {
-// val formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd-HH")
-// val localDateTime = java.time.LocalDateTime.parse(dateWithHourString, formatter)
-// java.util.Date.from(localDateTime.atZone(java.time.ZoneOffset.UTC).toInstant())
-// }
-// (rateLimit, rateLimitIds) <- RateLimitingUtil.getActiveRateLimitsWithIds(consumerId, date)
-// } yield {
-// (JSONFactory600.createActiveRateLimitsJsonV600FromCallLimit(rateLimit, rateLimitIds, date), HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getActiveRateLimitsNow,
-// implementedInApiVersion,
-// nameOf(getActiveRateLimitsNow),
-// "GET",
-// "/management/consumers/CONSUMER_ID/active-rate-limits",
-// "Get Active Rate Limits (Current)",
-// s"""
-// |Get the active rate limits for a consumer at the current date/time. Returns the aggregated rate limits from all active records at this moment.
-// |
-// |This is a convenience endpoint that uses the current date/time automatically.
-// |
-// |See ${Glossary.getGlossaryItemLink("Rate Limiting")} for more details on how rate limiting works.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// activeRateLimitsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidConsumerId,
-// ConsumerNotFoundByConsumerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetRateLimits)))
-//
-//
-// lazy val getActiveRateLimitsNow: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: "active-rate-limits" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetRateLimits, callContext)
-// _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// date = new java.util.Date() // Use current date/time
-// (rateLimit, rateLimitIds) <- RateLimitingUtil.getActiveRateLimitsWithIds(consumerId, date)
-// } yield {
-// (JSONFactory600.createActiveRateLimitsJsonV600FromCallLimit(rateLimit, rateLimitIds, date), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCurrentConsumer,
-// implementedInApiVersion,
-// nameOf(getCurrentConsumer),
-// "GET",
-// "/consumers/current",
-// "Get Current Consumer",
-// s"""Returns the consumer_id of the current authenticated consumer.
-// |
-// |This endpoint requires authentication via:
-// |* User authentication (OAuth, DirectLogin, etc.) - returns the consumer associated with the user's session
-// |* Consumer/Client authentication - returns the consumer credentials being used
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// EmptyBody,
-// CurrentConsumerJsonV600(
-// app_name = "SOFI",
-// app_type = "Web",
-// description = "Account Management",
-// consumer_id = "123",
-// active_rate_limits = activeRateLimitsJsonV600,
-// call_counters = redisCallCountersJsonV600
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidConsumerCredentials,
-// UnknownError
-// ),
-// apiTagConsumer :: apiTagApi :: Nil,
-// Some(List(canGetCurrentConsumer))
-// )
-//
-// staticResourceDocs += ResourceDoc(
-// getConsumer,
-// implementedInApiVersion,
-// nameOf(getConsumer),
-// "GET",
-// "/management/consumers/CONSUMER_ID",
-// "Get Consumer",
-// s"""Get the Consumer specified by CONSUMER_ID.
-// |
-// |This endpoint returns all consumer fields including:
-// |- Basic info: consumer_id, app_name, app_type, description, developer_email, company
-// |- OAuth: consumer_key, redirect_url
-// |- Status: enabled, created
-// |- Certificate: certificate_pem, certificate_info (subject, issuer, validity dates, PSD2 roles)
-// |- Branding: logo_url
-// |- Creator: created_by_user details
-// |- Rate limits: active_rate_limits showing current rate limiting configuration
-// |- Call counters: call_counters showing current API call usage from Redis
-// |
-// |Note: consumer_secret is never returned for security reasons.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// consumerJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ConsumerNotFoundByConsumerId,
-// UnknownError
-// ),
-// List(apiTagConsumer),
-// Some(List(canGetConsumers)),
-// authMode = UserOrApplication
-// )
-//
-// lazy val getConsumer: OBPEndpoint = {
-// case "management" :: "consumers" :: consumerId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetConsumers, callContext)
-// consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
-// // Get rate limits and call counters
-// currentConsumerCallCounters <- Future(RateLimitingUtil.consumerRateLimitState(consumer.consumerId.get).toList)
-// date = new java.util.Date()
-// (activeRateLimit, rateLimitIds) <- RateLimitingUtil.getActiveRateLimitsWithIds(consumer.consumerId.get, date)
-// activeRateLimitsJson = JSONFactory600.createActiveRateLimitsJsonV600FromCallLimit(activeRateLimit, rateLimitIds, date)
-// callCountersJson = JSONFactory600.createRedisCallCountersJson(currentConsumerCallCounters)
-// } yield {
-// (JSONFactory600.createConsumerJsonV600(consumer, None, activeRateLimitsJson, callCountersJson), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// invalidateCacheNamespace,
-// implementedInApiVersion,
-// nameOf(invalidateCacheNamespace),
-// "POST",
-// "/management/cache/namespaces/invalidate",
-// "Invalidate Cache Namespace",
-// """Invalidates a cache namespace by incrementing its version counter.
-// |
-// |This provides instant cache invalidation without deleting individual keys.
-// |Incrementing the version counter makes all keys with the old version unreachable.
-// |
-// |Available namespace IDs: call_counter, rl_active, rd_localised, rd_dynamic,
-// |rd_static, rd_all, swagger_static, connector, metrics_stable, metrics_recent, abac_rule
-// |
-// |Use after updating rate limits, translations, endpoints, or CBS data.
-// |
-// |Authentication is Required
-// |""",
-// InvalidateCacheNamespaceJsonV600(namespace_id = "rd_localised"),
-// InvalidatedCacheNamespaceJsonV600(
-// namespace_id = "rd_localised",
-// old_version = 1,
-// new_version = 2,
-// status = "invalidated"
-// ),
-// List(
-// InvalidJsonFormat,
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCache, apiTagSystem, apiTagApi),
-// Some(List(canInvalidateCacheNamespace))
-// )
-//
-// lazy val invalidateCacheNamespace: OBPEndpoint = {
-// case "management" :: "cache" :: "namespaces" :: "invalidate" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
-// json.extract[InvalidateCacheNamespaceJsonV600]
-// }
-// namespaceId = postJson.namespace_id
-// _ <- Helper.booleanToFuture(
-// s"$InvalidCacheNamespaceId $namespaceId. Valid values: ${Constant.ALL_CACHE_NAMESPACES.mkString(", ")}",
-// 400,
-// callContext
-// )(Constant.ALL_CACHE_NAMESPACES.contains(namespaceId))
-// oldVersion = Constant.getCacheNamespaceVersion(namespaceId)
-// newVersionOpt = Constant.incrementCacheNamespaceVersion(namespaceId)
-// _ <- Helper.booleanToFuture(
-// s"Failed to increment cache namespace version for: $namespaceId",
-// 500,
-// callContext
-// )(newVersionOpt.isDefined)
-// } yield {
-// val result = InvalidatedCacheNamespaceJsonV600(
-// namespace_id = namespaceId,
-// old_version = oldVersion,
-// new_version = newVersionOpt.get,
-// status = "invalidated"
-// )
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCacheConfig,
-// implementedInApiVersion,
-// nameOf(getCacheConfig),
-// "GET",
-// "/system/cache/config",
-// "Get Cache Configuration",
-// """Returns cache configuration information including:
-// |
-// |- Redis status: availability, connection details (URL, port, SSL)
-// |- In-memory cache status: availability and current size
-// |- Instance ID and environment
-// |- Global cache namespace prefix
-// |
-// |This helps understand what cache backend is being used and how it's configured.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// CacheConfigJsonV600(
-// redis_status = RedisCacheStatusJsonV600(
-// available = true,
-// url = "127.0.0.1",
-// port = 6379,
-// use_ssl = false
-// ),
-// in_memory_status = InMemoryCacheStatusJsonV600(
-// available = true,
-// current_size = 42
-// ),
-// instance_id = "obp",
-// environment = "dev",
-// global_prefix = "obp_dev_"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCache, apiTagSystem, apiTagApi),
-// Some(List(canGetCacheConfig))
-// )
-//
-// lazy val getCacheConfig: OBPEndpoint = {
-// case "system" :: "cache" :: "config" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetCacheConfig, callContext)
-// } yield {
-// val result = JSONFactory600.createCacheConfigJsonV600()
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCacheInfo,
-// implementedInApiVersion,
-// nameOf(getCacheInfo),
-// "GET",
-// "/system/cache/info",
-// "Get Cache Information",
-// """Returns detailed cache information for all namespaces:
-// |
-// |- Namespace ID and versioned prefix
-// |- Current version counter
-// |- Number of keys in each namespace
-// |- Description and category
-// |- Storage location (redis, memory, both, or unknown)
-// | - "redis": Keys stored in Redis
-// | - "memory": Keys stored in in-memory cache
-// | - "both": Keys in both locations (indicates a BUG - should never happen)
-// | - "unknown": No keys found, storage location cannot be determined
-// |- TTL info: Sampled TTL information from actual keys
-// | - Shows actual TTL values from up to 5 sample keys
-// | - Format: "123s" (fixed), "range 60s to 3600s (avg 1800s)" (variable), "no expiry" (persistent)
-// |- Total key count across all namespaces
-// |- Redis availability status
-// |
-// |This endpoint helps monitor cache usage and identify which namespaces contain the most data.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// CacheInfoJsonV600(
-// namespaces = List(
-// CacheNamespaceInfoJsonV600(
-// namespace_id = "call_counter",
-// prefix = "obp_dev_call_counter_1_",
-// current_version = 1,
-// key_count = 42,
-// description = "Rate limit call counters",
-// category = "Rate Limiting",
-// storage_location = "redis",
-// ttl_info = "range 60s to 86400s (avg 3600s)"
-// ),
-// CacheNamespaceInfoJsonV600(
-// namespace_id = "rd_localised",
-// prefix = "obp_dev_rd_localised_1_",
-// current_version = 1,
-// key_count = 128,
-// description = "Localized resource docs",
-// category = "API Documentation",
-// storage_location = "redis",
-// ttl_info = "3600s"
-// )
-// ),
-// total_keys = 170,
-// redis_available = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCache, apiTagSystem, apiTagApi),
-// Some(List(canGetCacheInfo))
-// )
-//
-// lazy val getCacheInfo: OBPEndpoint = {
-// case "system" :: "cache" :: "info" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetCacheInfo, callContext)
-// } yield {
-// val result = JSONFactory600.createCacheInfoJsonV600()
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDatabasePoolInfo,
-// implementedInApiVersion,
-// nameOf(getDatabasePoolInfo),
-// "GET",
-// "/system/database/pool",
-// "Get Database Pool Information",
-// """Returns HikariCP connection pool information including:
-// |
-// |- Pool name
-// |- Active connections: currently in use
-// |- Idle connections: available in pool
-// |- Total connections: active + idle
-// |- Threads awaiting connection: requests waiting for a connection
-// |- Configuration: max pool size, min idle, timeouts
-// |
-// |This helps diagnose connection pool issues such as connection leaks or pool exhaustion.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// DatabasePoolInfoJsonV600(
-// pool_name = "HikariPool-1",
-// active_connections = 5,
-// idle_connections = 3,
-// total_connections = 8,
-// threads_awaiting_connection = 0,
-// maximum_pool_size = 10,
-// minimum_idle = 2,
-// connection_timeout_ms = 30000,
-// idle_timeout_ms = 600000,
-// max_lifetime_ms = 1800000,
-// keepalive_time_ms = 0
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystem, apiTagApi),
-// Some(List(canGetDatabasePoolInfo))
-// )
-//
-// lazy val getDatabasePoolInfo: OBPEndpoint = {
-// case "system" :: "database" :: "pool" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetDatabasePoolInfo, callContext)
-// } yield {
-// val result = JSONFactory600.createDatabasePoolInfoJsonV600()
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getStoredProcedureConnectorHealth,
-// implementedInApiVersion,
-// nameOf(getStoredProcedureConnectorHealth),
-// "GET",
-// "/system/connectors/stored_procedure_vDec2019/health",
-// "Get Stored Procedure Connector Health",
-// """Returns health status of the stored procedure connector including:
-// |
-// |- Connection status (ok/error)
-// |- Database server name: identifies which backend node handled the request (useful for load balancer diagnostics)
-// |- Server IP address
-// |- Database name
-// |- Response time in milliseconds
-// |- Error message (if any)
-// |
-// |Supports database-specific queries for: SQL Server, PostgreSQL, Oracle, and MySQL/MariaDB.
-// |
-// |This endpoint is useful for diagnosing connectivity issues, especially when the database is behind a load balancer
-// |and you need to identify which node is responding or experiencing SSL certificate issues.
-// |
-// |Note: This endpoint may take a long time to respond if the database connection is slow or experiencing issues.
-// |The response time depends on the connection pool timeout and JDBC driver settings.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// StoredProcedureConnectorHealthJsonV600(
-// status = "ok",
-// server_name = Some("DBSERVER01"),
-// server_ip = Some("10.0.1.50"),
-// database_name = Some("obp_adapter"),
-// response_time_ms = 45,
-// error_message = None
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConnector, apiTagSystem, apiTagApi),
-// Some(List(canGetConnectorHealth))
-// )
-//
-// lazy val getStoredProcedureConnectorHealth: OBPEndpoint = {
-// case "system" :: "connectors" :: "stored_procedure_vDec2019" :: "health" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetConnectorHealth, callContext)
-// } yield {
-// val health = StoredProcedureUtils.getHealth()
-// val result = StoredProcedureConnectorHealthJsonV600(
-// status = health.status,
-// server_name = health.serverName,
-// server_ip = health.serverIp,
-// database_name = health.databaseName,
-// response_time_ms = health.responseTimeMs,
-// error_message = health.errorMessage
-// )
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBanks,
-// implementedInApiVersion,
-// nameOf(getBanks),
-// "GET",
-// "/banks",
-// "Get Banks",
-// """Get banks on this API instance
-// |Returns a list of banks supported on this server:
-// |
-// |- bank_id used as parameter in URLs
-// |- Short and full name of bank
-// |- Logo URL
-// |- Website
-// |
-// |User Authentication is Optional. The User need not be logged in.
-// |""",
-// EmptyBody,
-// BanksJsonV600(List(BankJsonV600(
-// bank_id = "gh.29.uk",
-// bank_code = "bank_code",
-// full_name = "full_name",
-// logo = "logo",
-// website = "www.openbankproject.com",
-// bank_routings = List(BankRoutingJsonV121("OBP", "gh.29.uk")),
-// attributes = Some(List(BankAttributeBankResponseJsonV400("OVERDRAFT_LIMIT", "1000")))
-// ))),
-// List(UnknownError),
-// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBanks: OBPEndpoint = {
-// case "banks" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (banks, callContext) <- NewStyle.function.getBanks(cc.callContext)
-// } yield {
-// (JSONFactory600.createBanksJsonV600(banks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBank,
-// implementedInApiVersion,
-// nameOf(getBank),
-// "GET",
-// "/banks/BANK_ID",
-// "Get Bank",
-// """Get the bank specified by BANK_ID
-// |Returns information about a single bank specified by BANK_ID including:
-// |
-// |- bank_id: The unique identifier of this bank
-// |- Short and full name of bank
-// |- Logo URL
-// |- Website
-// |""",
-// EmptyBody,
-// BankJsonV600(
-// bank_id = "gh.29.uk",
-// bank_code = "bank_code",
-// full_name = "full_name",
-// logo = "logo",
-// website = "www.openbankproject.com",
-// bank_routings = List(BankRoutingJsonV121("OBP", "gh.29.uk")),
-// attributes = Some(List(BankAttributeBankResponseJsonV400("OVERDRAFT_LIMIT", "1000")))
-// ),
-// List(UnknownError, BankNotFound),
-// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil
-// )
-//
-// lazy val getBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (bank, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (attributes, callContext) <- NewStyle.function.getBankAttributesByBank(bankId, callContext)
-// } yield {
-// (JSONFactory600.createBankJsonV600(bank, attributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTransactionsForBankAccount,
-// implementedInApiVersion,
-// nameOf(getTransactionsForBankAccount),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions",
-// "Get Transactions for Account (Full)",
-// s"""Returns transactions list of the account specified by ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |Authentication is required if the view is not public.
-// |
-// |${urlParametersDocument(true, true)}
-// |
-// |**Note:** This v6.0.0 endpoint returns `bank_id` directly in both `this_account` and `other_account` objects,
-// |making it easier to identify which bank each account belongs to without parsing the `bank_routing` object.
-// |
-// |""",
-// EmptyBody,
-// TransactionsJsonV600(List(TransactionJsonV600(
-// transaction_id = "123",
-// this_account = ThisAccountJsonV600(
-// bank_id = "gh.29.uk",
-// account_id = "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// bank_routing = BankRoutingJsonV121("OBP", "gh.29.uk"),
-// account_routings = List(AccountRoutingJsonV121("OBP", "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0")),
-// holders = List(AccountHolderJSON("John Doe", false))
-// ),
-// other_account = OtherAccountJsonV600(
-// bank_id = "other.bank.uk",
-// account_id = "counterparty-123",
-// holder = AccountHolderJSON("Jane Smith", false),
-// bank_routing = BankRoutingJsonV121("OBP", "other.bank.uk"),
-// account_routings = List(AccountRoutingJsonV121("OBP", "counterparty-123")),
-// metadata = otherAccountMetadataJSON
-// ),
-// details = TransactionDetailsJSON(
-// `type` = "SEPA",
-// description = "Payment for services",
-// posted = new java.util.Date(),
-// completed = new java.util.Date(),
-// new_balance = AmountOfMoneyJsonV121("EUR", "1000.00"),
-// value = AmountOfMoneyJsonV121("EUR", "100.00")
-// ),
-// metadata = transactionMetadataJSON,
-// transaction_attributes = Nil
-// ))),
-// List(
-// FilterSortDirectionError,
-// FilterOffersetError,
-// FilterLimitError,
-// FilterDateFormatError,
-// AuthenticatedUserIsRequired,
-// BankAccountNotFound,
-// ViewNotFound,
-// UnknownError
-// ),
-// List(apiTagTransaction, apiTagAccount)
-// )
-//
-// lazy val getTransactionsForBankAccount: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transactions" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user, callContext) <- authenticatedAccess(cc)
-// (bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (bankAccount, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
-// view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankAccount.bankId, bankAccount.accountId), user, callContext)
-// (params, callContext) <- createQueriesByHttpParamsFuture(callContext.get.requestHeaders, callContext)
-// (transactions, callContext) <- bankAccount.getModeratedTransactionsFuture(bank, user, view, callContext, params) map {
-// connectorEmptyResponse(_, callContext)
-// }
-// moderatedTransactionsWithAttributes <- Future.sequence(transactions.map(transaction =>
-// NewStyle.function.getTransactionAttributes(
-// bankId,
-// transaction.id,
-// cc.callContext: Option[CallContext]).map(attributes => code.api.v3_0_0.ModeratedTransactionWithAttributes(transaction, attributes._1))
-// ))
-// } yield {
-// (JSONFactory600.createTransactionsJsonV600(moderatedTransactionsWithAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// lazy val getCurrentConsumer: OBPEndpoint = {
-// case "consumers" :: "current" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// consumer <- Future {
-// cc.consumer match {
-// case Full(c) => Full(c)
-// case _ => Empty
-// }
-// } map {
-// unboxFullOrFail(_, cc.callContext, InvalidConsumerCredentials, 401)
-// }
-// currentConsumerCallCounters <- Future(RateLimitingUtil.consumerRateLimitState(consumer.consumerId.get).toList)
-// date = new java.util.Date()
-// (activeRateLimit, rateLimitIds) <- RateLimitingUtil.getActiveRateLimitsWithIds(consumer.consumerId.get, date)
-// activeRateLimitsJson = JSONFactory600.createActiveRateLimitsJsonV600FromCallLimit(activeRateLimit, rateLimitIds, date)
-// callCountersJson = createRedisCallCountersJson(currentConsumerCallCounters)
-// } yield {
-// (CurrentConsumerJsonV600(consumer.name.get, consumer.appType.get, consumer.description.get, consumer.consumerId.get, activeRateLimitsJson, callCountersJson), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getDynamicEntityDiagnostics,
-// implementedInApiVersion,
-// nameOf(getDynamicEntityDiagnostics),
-// "GET",
-// "/management/diagnostics/dynamic-entities",
-// "Get Dynamic Entity Diagnostics",
-// s"""Get diagnostic information about Dynamic Entities to help troubleshoot Swagger generation issues.
-// |
-// |**Use Case:**
-// |This endpoint is particularly useful when:
-// |* The Swagger endpoint (`/obp/v6.0.0/resource-docs/OBPv6.0.0/swagger?content=dynamic`) fails with errors like "expected boolean"
-// |* The OBP endpoint (`/obp/v6.0.0/resource-docs/OBPv6.0.0/obp?content=dynamic`) works fine
-// |* You need to identify which dynamic entity has malformed field definitions
-// |
-// |**What It Checks:**
-// |This endpoint analyzes all dynamic entities (both system and bank level) for:
-// |* Boolean fields with invalid example values (e.g., actual JSON booleans or invalid strings instead of `"true"` or `"false"`)
-// |* Malformed JSON in field definitions
-// |* Fields that cannot be converted to their declared types
-// |* Other validation issues that cause Swagger generation to fail
-// |
-// |**Response Format:**
-// |The response contains:
-// |* `issues` - List of issues found, each with:
-// | * `entity_name` - Name of the problematic entity
-// | * `bank_id` - Bank ID (or "SYSTEM_LEVEL" for system entities)
-// | * `field_name` - Name of the problematic field
-// | * `example_value` - The current (invalid) example value
-// | * `error_message` - Description of what's wrong and how to fix it
-// |* `total_issues` - Count of total issues found
-// |* `scanned_entities` - List of all dynamic entities that were scanned (format: "EntityName (BANK_ID)" or "EntityName (SYSTEM)")
-// |
-// |**How to Fix Issues:**
-// |1. Identify the problematic entity from the diagnostic output
-// |2. Update the entity definition using PUT `/management/system-dynamic-entities/DYNAMIC_ENTITY_ID` or PUT `/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID`
-// |3. For boolean fields, ensure the example value is either `"true"` or `"false"` (as strings)
-// |4. Re-run this diagnostic to verify the fix
-// |5. Check that the Swagger endpoint now works
-// |
-// |**Example Issue:**
-// |```
-// |{
-// | "entity_name": "Customer",
-// | "bank_id": "gh.29.uk",
-// | "field_name": "is_active",
-// | "example_value": "malformed_value",
-// | "error_message": "Boolean field has invalid example value. Expected 'true' or 'false', got: 'malformed_value'"
-// |}
-// |```
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |**Required Role:** `CanGetDynamicEntityDiagnostics`
-// |
-// |If no issues are found, the response will contain an empty issues list with `total_issues: 0`, but `scanned_entities` will show which entities were checked.
-// |""",
-// EmptyBody,
-// DynamicEntityDiagnosticsJsonV600(
-// scanned_entities = List("MyEntity (gh.29.uk)", "AnotherEntity (SYSTEM)"),
-// issues = List(
-// DynamicEntityIssueJsonV600(
-// entity_name = "MyEntity",
-// bank_id = "gh.29.uk",
-// field_name = "is_active",
-// example_value = "malformed_value",
-// error_message = "Boolean field has invalid example value. Expected 'true' or 'false', got: 'malformed_value'"
-// )
-// ),
-// total_issues = 1,
-// orphaned_entities = List(
-// OrphanedDynamicEntityJsonV600(
-// entity_name = "OldEntity",
-// bank_id = "gh.29.uk",
-// record_count = 42
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicEntity, apiTagApi),
-// Some(List(canGetDynamicEntityDiagnostics))
-// )
-//
-// lazy val getDynamicEntityDiagnostics: OBPEndpoint = {
-// case "management" :: "diagnostics" :: "dynamic-entities" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetDynamicEntityDiagnostics, callContext)
-// } yield {
-// val result = DiagnosticDynamicEntityCheck.checkAllDynamicEntities()
-// val issuesJson = result.issues.map { issue =>
-// DynamicEntityIssueJsonV600(
-// entity_name = issue.entityName,
-// bank_id = issue.bankId.getOrElse("SYSTEM_LEVEL"),
-// field_name = issue.fieldName,
-// example_value = issue.exampleValue,
-// error_message = issue.errorMessage
-// )
-// }
-// val orphanedJson = result.orphanedEntities.map { orphan =>
-// OrphanedDynamicEntityJsonV600(
-// entity_name = orphan.entityName,
-// bank_id = orphan.bankId,
-// record_count = orphan.recordCount
-// )
-// }
-// val response = DynamicEntityDiagnosticsJsonV600(result.scannedEntities, issuesJson, result.issues.length, orphanedJson)
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// cleanupOrphanedDynamicEntityRecords,
-// implementedInApiVersion,
-// nameOf(cleanupOrphanedDynamicEntityRecords),
-// "DELETE",
-// "/management/diagnostics/dynamic-entities/orphaned-records",
-// "Cleanup Orphaned Dynamic Entity Records",
-// s"""Delete orphaned dynamic entity data records.
-// |
-// |Orphaned records are rows in the DynamicData table whose entityName/bankId combination
-// |has no matching Dynamic Entity definition. These can accumulate when entity definitions
-// |are deleted but their data records are not cleaned up.
-// |
-// |This endpoint first identifies all orphaned records (using the same detection logic as
-// |GET /management/diagnostics/dynamic-entities), then deletes them.
-// |
-// |**Response Format:**
-// |* `deleted_orphaned_entities` - List of orphaned entity groups that were deleted, each with:
-// | * `entity_name` - Name of the orphaned entity
-// | * `bank_id` - Bank ID (or empty string for system-level)
-// | * `record_count` - Number of records that were deleted for this entity group
-// |* `total_records_deleted` - Total count of all deleted records
-// |
-// |Authentication is Required
-// |
-// |**Required Role:** `CanCleanupOrphanedDynamicEntityRecords`
-// |""",
-// EmptyBody,
-// CleanupOrphanedDynamicEntityResponseJsonV600(
-// deleted_orphaned_entities = List(
-// OrphanedDynamicEntityJsonV600(
-// entity_name = "OldEntity",
-// bank_id = "gh.29.uk",
-// record_count = 42
-// )
-// ),
-// total_records_deleted = 42
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicEntity, apiTagApi),
-// Some(List(canCleanupOrphanedDynamicEntityRecords))
-// )
-//
-// lazy val cleanupOrphanedDynamicEntityRecords: OBPEndpoint = {
-// case "management" :: "diagnostics" :: "dynamic-entities" :: "orphaned-records" :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCleanupOrphanedDynamicEntityRecords, callContext)
-// } yield {
-// // Get all entity definitions (both bank and system level)
-// val definitions = DynamicEntityProvider.connectorMethodProvider.vend.getDynamicEntities(None, true)
-// // Identify orphaned records
-// val orphaned = DiagnosticDynamicEntityCheck.checkOrphanedRecords(definitions)
-// // Delete orphaned data records for each orphaned entity group
-// var totalDeleted: Long = 0
-// orphaned.foreach { orphan =>
-// val bankIdOption = if (orphan.bankId.isEmpty) None else Some(orphan.bankId)
-// val records = bankIdOption match {
-// case None =>
-// DynamicData.findAll(
-// By(DynamicData.DynamicEntityName, orphan.entityName),
-// NullRef(DynamicData.BankId)
-// )
-// case Some(bid) =>
-// DynamicData.findAll(
-// By(DynamicData.DynamicEntityName, orphan.entityName),
-// By(DynamicData.BankId, bid)
-// )
-// }
-// records.foreach { record =>
-// record.delete_!
-// totalDeleted += 1
-// }
-// }
-// // Build response
-// val orphanedJson = orphaned.map { o =>
-// OrphanedDynamicEntityJsonV600(o.entityName, o.bankId, o.recordCount)
-// }
-// (CleanupOrphanedDynamicEntityResponseJsonV600(orphanedJson, totalDeleted), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getReferenceTypes,
-// implementedInApiVersion,
-// nameOf(getReferenceTypes),
-// "GET",
-// "/management/dynamic-entities/reference-types",
-// "Get Reference Types for Dynamic Entities",
-// s"""Get a list of all available reference types that can be used in Dynamic Entity field definitions.
-// |
-// |Reference types allow Dynamic Entity fields to reference other entities (similar to foreign keys).
-// |This endpoint returns both:
-// |* **Static reference types** - Built-in reference types for core OBP entities (e.g., Customer, Account, Transaction)
-// |* **Dynamic reference types** - Reference types for Dynamic Entities that have been created
-// |
-// |Each reference type includes:
-// |* `type_name` - The full reference type string to use in entity definitions (e.g., "reference:Customer")
-// |* `example_value` - An example value showing the correct format
-// |* `description` - Description of what the reference type represents
-// |
-// |**Use Case:**
-// |When creating a Dynamic Entity with a field that references another entity, you need to know:
-// |1. What reference types are available
-// |2. The correct format for the type name
-// |3. The correct format for example values
-// |
-// |This endpoint provides all that information.
-// |
-// |**Example Usage:**
-// |If you want to create a Dynamic Entity with a field that references a Customer, you would:
-// |1. Call this endpoint to see that "reference:Customer" is available
-// |2. Use it in your entity definition like:
-// |```json
-// |{
-// | "customer_id": {
-// | "type": "reference:Customer",
-// | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388"
-// | }
-// |}
-// |```
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |**Required Role:** `CanGetDynamicEntityReferenceTypes`
-// |""",
-// EmptyBody,
-// ReferenceTypesJsonV600(
-// reference_types = List(
-// ReferenceTypeJsonV600(
-// type_name = "reference:Customer",
-// example_value = "a8770fca-3d1d-47af-b6d0-7a6c3f124388",
-// description = "Reference to a Customer entity"
-// ),
-// ReferenceTypeJsonV600(
-// type_name = "reference:Account:BANK_ID&ACCOUNT_ID",
-// example_value = "BANK_ID=b9881ecb-4e2e-58bg-c7e1-8b7d4e235499&ACCOUNT_ID=c0992fdb-5f3f-69ch-d8f2-9c8e5f346600",
-// description = "Composite reference to an Account by bank ID and account ID"
-// ),
-// ReferenceTypeJsonV600(
-// type_name = "reference:MyDynamicEntity",
-// example_value = "d1aa3gec-6g4g-70di-e9g3-0d9f6g457711",
-// description = "Reference to MyDynamicEntity (dynamic entity)"
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagDynamicEntity, apiTagApi),
-// Some(List(canGetDynamicEntityReferenceTypes))
-// )
-//
-// lazy val getReferenceTypes: OBPEndpoint = {
-// case "management" :: "dynamic-entities" :: "reference-types" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetDynamicEntityReferenceTypes, callContext)
-// } yield {
-// val referenceTypeNames = code.dynamicEntity.ReferenceType.referenceTypeNames
-//
-// // Get list of dynamic entity names to distinguish from static references
-// val dynamicEntityNames = NewStyle.function.getDynamicEntities(None, true)
-// .map(entity => s"reference:${entity.entityName}")
-// .toSet
-//
-// val exampleId1 = APIUtil.generateUUID()
-// val exampleId2 = APIUtil.generateUUID()
-// val exampleId3 = APIUtil.generateUUID()
-// val exampleId4 = APIUtil.generateUUID()
-//
-// val reg1 = """reference:([^:]+)""".r
-// val reg2 = """reference:(?:[^:]+):([^&]+)&([^&]+)""".r
-// val reg3 = """reference:(?:[^:]+):([^&]+)&([^&]+)&([^&]+)""".r
-// val reg4 = """reference:(?:[^:]+):([^&]+)&([^&]+)&([^&]+)&([^&]+)""".r
-//
-// val referenceTypes = referenceTypeNames.map { refTypeName =>
-// val example = refTypeName match {
-// case reg1(entityName) =>
-// val description = if (dynamicEntityNames.contains(refTypeName)) {
-// s"Reference to $entityName (dynamic entity)"
-// } else {
-// s"Reference to $entityName entity"
-// }
-// (exampleId1, description)
-// case reg2(a, b) =>
-// (s"$a=$exampleId1&$b=$exampleId2", s"Composite reference with $a and $b")
-// case reg3(a, b, c) =>
-// (s"$a=$exampleId1&$b=$exampleId2&$c=$exampleId3", s"Composite reference with $a, $b and $c")
-// case reg4(a, b, c, d) =>
-// (s"$a=$exampleId1&$b=$exampleId2&$c=$exampleId3&$d=$exampleId4", s"Composite reference with $a, $b, $c and $d")
-// case _ => (exampleId1, "Reference type")
-// }
-//
-// ReferenceTypeJsonV600(
-// type_name = refTypeName,
-// example_value = example._1,
-// description = example._2
-// )
-// }
-//
-// val response = ReferenceTypesJsonV600(referenceTypes)
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCurrentUser,
-// implementedInApiVersion,
-// nameOf(getCurrentUser), // TODO can we get this string from the val two lines above?
-// "GET",
-// "/users/current",
-// "Get User (Current)",
-// s"""Get the logged in user
-// |
-// |${userAuthenticationMessage(true)}
-// """.stripMargin,
-// EmptyBody,
-// userJsonV300,
-// List(AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagUser))
-//
-// lazy val getCurrentUser: OBPEndpoint = {
-// case "users" :: "current" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// entitlements <- NewStyle.function.getEntitlementsByUserId(u.userId, callContext)
-// } yield {
-// val permissions: Option[Permission] = Views.views.vend.getPermissionForUser(u).toOption
-// // Add virtual entitlements for super_admin_user_ids or oidc_operator_user_ids
-// val virtualRoleNames = if (APIUtil.isSuperAdmin(u.userId)) {
-// JSONFactory200.superAdminVirtualRoles
-// } else if (APIUtil.isOidcOperator(u.userId)) {
-// JSONFactory200.oidcOperatorVirtualRoles
-// } else {
-// List.empty
-// }
-// val existingRoleNames = entitlements.map(_.roleName).toSet
-// val virtualEntitlements = virtualRoleNames.filterNot(existingRoleNames.contains).map { role =>
-// new Entitlement {
-// def entitlementId: String = ""
-// def bankId: String = ""
-// def userId: String = u.userId
-// def roleName: String = role
-// def createdByProcess: String = if (APIUtil.isSuperAdmin(u.userId)) "super_admin_user_ids" else "oidc_operator_user_ids"
-// def entitlementRequestId: Option[String] = None
-// def groupId: Option[String] = None
-// def process: Option[String] = None
-// }
-// }
-// val finalEntitlements = entitlements ::: virtualEntitlements
-// val currentUser = UserV600(u, finalEntitlements, permissions)
-// val onBehalfOfUser = if(cc.onBehalfOfUser.isDefined) {
-// val user = cc.onBehalfOfUser.toOption.get
-// val entitlements = Entitlement.entitlement.vend.getEntitlementsByUserId(user.userId).headOption.toList.flatten
-// val permissions: Option[Permission] = Views.views.vend.getPermissionForUser(user).toOption
-// Some(UserV600(user, entitlements, permissions))
-// } else {
-// None
-// }
-// (JSONFactory600.createUserInfoJSON(currentUser, onBehalfOfUser), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUsers,
-// implementedInApiVersion,
-// nameOf(getUsers),
-// "GET",
-// "/users",
-// "Get all Users",
-// s"""Get all users, optionally filtered.
-// |
-// |All query parameters are optional and may be combined.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetAnyUser entitlement is required.
-// |
-// |${urlParametersDocument(false, false)}
-// |* provider (if null ignore) - filter by identity provider, exact match
-// |* username (if null ignore) - filter by username, exact match
-// |* email (if null ignore) - filter by email, exact match (may return multiple users — duplicate emails are allowed in OBP by design)
-// |* user_id (if null ignore) - filter by user_id, exact match
-// |* locked_status (if null ignore) - "active" or "locked"
-// |* is_deleted (default: false)
-// |* role_name (if null ignore) - filter by entitlement/role name e.g. CanCreateAccount
-// |* bank_id (if null ignore) - when used with role_name, filter entitlements by bank_id
-// |* sort_by (if null ignore) - sort by field; allowed values: ${code.users.DoobieUserQueries.SortableColumns.keySet.toSeq.sorted.mkString(", ")}
-// |* sort_direction (if null defaults to DESC) - "asc" or "desc" (case-insensitive)
-// |
-// |When sort_by is omitted, results are ordered by insertion order ascending (stable pagination).
-// |
-// |Returns an empty list (not 404) when no users match.
-// |
-// """.stripMargin,
-// EmptyBody,
-// usersInfoJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// FilterSortByError,
-// FilterSortByNotAllowedForEndpoint,
-// FilterSortDirectionError,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUsers: OBPEndpoint = {
-// case "users" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// logger.info(s"getUsers says: GET /users called, url=${cc.url}")
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ = logger.info(s"getUsers says: authenticated user_id=${u.userId} provider=${u.provider}")
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetAnyUser, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(
-// httpParams,
-// callContext
-// )
-// _ <- Future {
-// val requestedSort = obpQueryParams.collectFirst { case OBPSortBy(v) => v }
-// val allowed = code.users.DoobieUserQueries.SortableColumns.keySet
-// val valid: Box[Unit] = requestedSort match {
-// case Some(v) if !allowed.contains(v) =>
-// Failure(ErrorMessages.filterSortByNotAllowedForEndpointDetail("GET /users", v, allowed))
-// case _ => Full(())
-// }
-// unboxFullOrFail(valid, callContext, ErrorMessages.FilterSortByNotAllowedForEndpoint, 400)
-// }
-// rows <- code.users.Users.users.vend.getUsersV600F(obpQueryParams)
-// _ = logger.info(s"getUsers says: returning ${rows.size} user(s) to user_id=${u.userId}")
-// } yield {
-// (JSONFactory600.createUsersInfoJsonV600(rows), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserByUserId,
-// implementedInApiVersion,
-// nameOf(getUserByUserId),
-// "GET",
-// "/users/user-id/USER_ID",
-// "Get User by USER_ID",
-// s"""Get user by USER_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetAnyUser entitlement is required,
-// |
-// """.stripMargin,
-// EmptyBody,
-// userInfoDetailJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canGetAnyUser))
-// )
-//
-// lazy val getUserByUserId: OBPEndpoint = {
-// case "users" :: "user-id" :: userId :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// user <- Users.users.vend.getUserByUserIdFuture(userId) map {
-// x => unboxFullOrFail(x, callContext, s"$UserNotFoundByUserId Current UserId($userId)")
-// }
-// entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, callContext)
-// // Fetch user agreements
-// agreements <- Future {
-// val acceptMarketingInfo = UserAgreementProvider.userAgreementProvider.vend.getLastUserAgreement(user.userId, "accept_marketing_info")
-// val termsAndConditions = UserAgreementProvider.userAgreementProvider.vend.getLastUserAgreement(user.userId, "terms_and_conditions")
-// val privacyConditions = UserAgreementProvider.userAgreementProvider.vend.getLastUserAgreement(user.userId, "privacy_conditions")
-// val agreementList = acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList
-// if (agreementList.isEmpty) None else Some(agreementList)
-// }
-// isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
-// authUser = code.model.dataAccess.AuthUser.find(
-// By(code.model.dataAccess.AuthUser.user, user.userPrimaryKey.value)
-// )
-// // Fetch metrics data for the user
-// userMetrics <- Future {
-// code.metrics.MappedMetric.findAll(
-// By(code.metrics.MappedMetric.userId, userId),
-// OrderBy(code.metrics.MappedMetric.date, Descending),
-// MaxRows(5)
-// )
-// }
-// lastActivityDate = userMetrics.headOption.map(_.getDate())
-// recentOperationIds = userMetrics.map(_.getImplementedByPartialFunction()).distinct.take(5)
-// } yield {
-// (JSONFactory600.createUserInfoJsonV600(
-// user,
-// authUser.map(_.firstName.get).getOrElse(""),
-// authUser.map(_.lastName.get).getOrElse(""),
-// entitlements,
-// agreements,
-// isLocked,
-// lastActivityDate,
-// recentOperationIds
-// ), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMigrations,
-// implementedInApiVersion,
-// nameOf(getMigrations),
-// "GET",
-// "/system/migrations",
-// "Get Database Migrations",
-// s"""Get all database migration script logs.
-// |
-// |This endpoint returns information about all migration scripts that have been executed or attempted.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetMigrations entitlement is required.
-// |
-// """.stripMargin,
-// EmptyBody,
-// migrationScriptLogsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystem, apiTagApi),
-// Some(List(canGetMigrations))
-// )
-//
-// lazy val getMigrations: OBPEndpoint = {
-// case "system" :: "migrations" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetMigrations, callContext)
-// } yield {
-// val migrations = code.migration.MigrationScriptLogProvider.migrationScriptLogProvider.vend.getMigrationScriptLogs()
-// (JSONFactory600.createMigrationScriptLogsJsonV600(migrations), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCacheNamespaces,
-// implementedInApiVersion,
-// nameOf(getCacheNamespaces),
-// "GET",
-// "/system/cache/namespaces",
-// "Get Cache Namespaces",
-// """Returns information about all cache namespaces in the system.
-// |
-// |This endpoint provides visibility into:
-// |* Cache namespace prefixes and their purposes
-// |* Number of keys in each namespace
-// |* TTL configurations
-// |* Example keys for each namespace
-// |
-// |This is useful for:
-// |* Monitoring cache usage
-// |* Understanding cache structure
-// |* Debugging cache-related issues
-// |* Planning cache management operations
-// |
-// |""",
-// EmptyBody,
-// CacheNamespacesJsonV600(
-// namespaces = List(
-// CacheNamespaceJsonV600(
-// prefix = "call_counter_",
-// description = "Rate limiting counters per consumer and time period",
-// ttl_seconds = "varies",
-// category = "Rate Limiting",
-// key_count = 42,
-// example_key = "rl_counter_consumer123_PER_MINUTE"
-// ),
-// CacheNamespaceJsonV600(
-// prefix = "rl_active_",
-// description = "Active rate limit configurations",
-// ttl_seconds = "3600",
-// category = "Rate Limiting",
-// key_count = 15,
-// example_key = "rl_active_consumer123_2024-12-27-14"
-// ),
-// CacheNamespaceJsonV600(
-// prefix = "rd_localised_",
-// description = "Localized resource documentation",
-// ttl_seconds = "3600",
-// category = "Resource Documentation",
-// key_count = 128,
-// example_key = "rd_localised_operationId:getBanks-locale:en"
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCache, apiTagSystem, apiTagApi),
-// Some(List(canGetCacheNamespaces))
-// )
-//
-// lazy val getCacheNamespaces: OBPEndpoint = {
-// case "system" :: "cache" :: "namespaces" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetCacheNamespaces, callContext)
-// } yield {
-// // Define known cache namespaces with their metadata
-// val namespaces = List(
-// // Rate Limiting
-// (Constant.CALL_COUNTER_PREFIX, "Rate limiting counters per consumer and time period", "varies", "Rate Limiting"),
-// (Constant.RATE_LIMIT_ACTIVE_PREFIX, "Active rate limit configurations", Constant.RATE_LIMIT_ACTIVE_CACHE_TTL.toString, "Rate Limiting"),
-// // Resource Documentation
-// (Constant.LOCALISED_RESOURCE_DOC_PREFIX, "Localized resource documentation", Constant.CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL.toString, "Resource Documentation"),
-// (Constant.DYNAMIC_RESOURCE_DOC_CACHE_KEY_PREFIX, "Dynamic resource documentation", Constant.GET_DYNAMIC_RESOURCE_DOCS_TTL.toString, "Resource Documentation"),
-// (Constant.STATIC_RESOURCE_DOC_CACHE_KEY_PREFIX, "Static resource documentation", Constant.GET_STATIC_RESOURCE_DOCS_TTL.toString, "Resource Documentation"),
-// (Constant.ALL_RESOURCE_DOC_CACHE_KEY_PREFIX, "All resource documentation", Constant.GET_STATIC_RESOURCE_DOCS_TTL.toString, "Resource Documentation"),
-// (Constant.STATIC_SWAGGER_DOC_CACHE_KEY_PREFIX, "Swagger documentation", Constant.GET_STATIC_RESOURCE_DOCS_TTL.toString, "Resource Documentation"),
-// // Connector
-// (Constant.CONNECTOR_PREFIX, "Connector method names and metadata", "3600", "Connector"),
-// // Metrics
-// (Constant.METRICS_STABLE_PREFIX, "Stable metrics (historical)", "86400", "Metrics"),
-// (Constant.METRICS_RECENT_PREFIX, "Recent metrics", "7", "Metrics"),
-// // ABAC
-// (Constant.ABAC_RULE_PREFIX, "ABAC rule cache", "indefinite", "ABAC")
-// ).map { case (prefix, description, ttl, category) =>
-// // Get actual key count and example from Redis
-// val keyCount = Redis.countKeys(s"${prefix}*")
-// val exampleKey = Redis.getSampleKey(s"${prefix}*")
-// JSONFactory600.createCacheNamespaceJsonV600(
-// prefix = prefix,
-// description = description,
-// ttlSeconds = ttl,
-// category = category,
-// keyCount = keyCount,
-// exampleKey = exampleKey
-// )
-// }
-//
-// (JSONFactory600.createCacheNamespacesJsonV600(namespaces), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestCardano,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestCardano),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/CARDANO/transaction-requests",
-// "Create Transaction Request (CARDANO)",
-// s"""
-// |
-// |For sandbox mode, it will use the Cardano Preprod Network.
-// |The accountId can be the wallet_id for now, as it uses cardano-wallet in the backend.
-// |
-// |${transactionRequestGeneralText}
-// |
-// """.stripMargin,
-// transactionRequestBodyCardanoJsonV600,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestCardano: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
-// "CARDANO" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("CARDANO")
-// LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestEthereumeSendTransaction,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestEthereumeSendTransaction),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_TRANSACTION/transaction-requests",
-// "Create Transaction Request (ETH_SEND_TRANSACTION)",
-// s"""
-// |
-// |Send ETH via Ethereum JSON-RPC.
-// |AccountId should hold the 0x address for now.
-// |
-// |${transactionRequestGeneralText}
-// |
-// """.stripMargin,
-// transactionRequestBodyEthereumJsonV600,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestEthereumeSendTransaction: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
-// "ETH_SEND_TRANSACTION" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("ETH_SEND_TRANSACTION")
-// LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
-// }
-// staticResourceDocs += ResourceDoc(
-// createTransactionRequestEthSendRawTransaction,
-// implementedInApiVersion,
-// nameOf(createTransactionRequestEthSendRawTransaction),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_RAW_TRANSACTION/transaction-requests",
-// "CREATE TRANSACTION REQUEST (ETH_SEND_RAW_TRANSACTION )",
-// s"""
-// |
-// |Send ETH via Ethereum JSON-RPC.
-// |AccountId should hold the 0x address for now.
-// |
-// |${transactionRequestGeneralText}
-// |
-// """.stripMargin,
-// transactionRequestBodyEthSendRawTransactionJsonV600,
-// transactionRequestWithChargeJSON400,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// InsufficientAuthorisationToCreateTransactionRequest,
-// InvalidTransactionRequestType,
-// InvalidJsonFormat,
-// NotPositiveAmount,
-// InvalidTransactionRequestCurrency,
-// TransactionDisabled,
-// UnknownError
-// ),
-// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
-// )
-//
-// lazy val createTransactionRequestEthSendRawTransaction: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
-// "ETH_SEND_RAW_TRANSACTION" :: "transaction-requests" :: Nil JsonPost json -> _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val transactionRequestType = TransactionRequestType("ETH_SEND_RAW_TRANSACTION")
-// LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// createBank,
-// implementedInApiVersion,
-// "createBank",
-// "POST",
-// "/banks",
-// "Create Bank",
-// s"""Create a new bank (Authenticated access).
-// |
-// |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.
-// |Thus the User can manage the bank they create and assign Roles to other Users.
-// |
-// Only SANDBOX mode (i.e. when connector=mapped in properties file)
-// |The settlement accounts are automatically created by the system when the bank is created.
-// |Name and account id are created in accordance to the next rules:
-// | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)
-// | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)
-// |
-// |""",
-//
-// postBankJson600,
-// bankJson600,
-// List(
-// InvalidJsonFormat,
-// $AuthenticatedUserIsRequired,
-// InsufficientAuthorisationToCreateBank,
-// UnknownError
-// ),
-// List(apiTagBank),
-// Some(List(canCreateBank))
-// )
-//
-// lazy val createBank: OBPEndpoint = {
-// case "banks" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// val failMsg = s"$InvalidJsonFormat The Json body should be the $PostBankJson600 "
-// // Catch the common v4/v5 → v6 field-rename mistakes before extraction.
-// // Without this, sending {"id": "..."} silently produces an empty bank_id
-// // and fails downstream with a confusing BANK_ID length-validation error.
-// val deprecatedFieldHints: List[String] = json match {
-// case JObject(fields) => fields.collect {
-// case JField("id", _) =>
-// "'id' was renamed to 'bank_id' in v6.0.0 (it was the field name in v4.0.0 and v5.0.0)"
-// case JField("short_name", _) =>
-// "'short_name' was removed in v5.0.0 (it only existed in v4.0.0)"
-// }
-// case _ => Nil
-// }
-// for {
-// _ <- Helper.booleanToFuture(
-// failMsg = s"$InvalidJsonFormat Deprecated request-body field(s): ${deprecatedFieldHints.mkString("; ")}. The v6.0.0 createBank body shape is: bank_id, bank_code, full_name, logo, website, bank_routings.",
-// cc = cc.callContext
-// ) {
-// deprecatedFieldHints.isEmpty
-// }
-// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// json.extract[PostBankJson600]
-// }
-//
-// // TODO: Improve this error message to not hardcode "16" - should reference the max length from checkOptionalShortString function
-// checkShortStringValue = APIUtil.checkOptionalShortString(postJson.bank_id)
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID: $checkShortStringValue BANK_ID must contain only characters A-Z, a-z, 0-9, -, _, . and be max 16 characters.", cc = cc.callContext) {
-// checkShortStringValue == SILENCE_IS_GOLDEN
-// }
-//
-// _ <- Helper.booleanToFuture(failMsg = ErrorMessages.InvalidConsumerCredentials, cc = cc.callContext) {
-// cc.callContext.map(_.consumer.isDefined == true).isDefined
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", cc = cc.callContext) {
-// postJson.bank_id.length > 3
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain space characters", cc = cc.callContext) {
-// !postJson.bank_id.contains(" ")
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain `::::` characters", cc = cc.callContext) {
-// !`checkIfContains::::`(postJson.bank_id)
-// }
-// (banks, callContext) <- NewStyle.function.getBanks(cc.callContext)
-// _ <- Helper.booleanToFuture(failMsg = ErrorMessages.bankIdAlreadyExists, failCode = 409, cc = cc.callContext) {
-// !banks.exists { b => b.bankId.value == postJson.bank_id }
-// }
-// (success, callContext) <- NewStyle.function.createOrUpdateBank(
-// postJson.bank_id,
-// postJson.full_name.getOrElse(""),
-// postJson.bank_code,
-// postJson.logo.getOrElse(""),
-// postJson.website.getOrElse(""),
-// postJson.bank_routings.getOrElse(Nil).find(_.scheme == "BIC").map(_.address).getOrElse(""),
-// "",
-// postJson.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.scheme).getOrElse(""),
-// postJson.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.address).getOrElse(""),
-// callContext
-// )
-// entitlements <- NewStyle.function.getEntitlementsByUserId(cc.userId, callContext)
-// entitlementsByBank = entitlements.filter(_.bankId == postJson.bank_id)
-// _ <- entitlementsByBank.exists(_.roleName == CanCreateEntitlementAtOneBank.toString()) match {
-// case true =>
-// // Already has entitlement
-// Future(())
-// case false =>
-// Future(Entitlement.entitlement.vend.addEntitlement(postJson.bank_id, cc.userId, CanCreateEntitlementAtOneBank.toString()))
-// }
-// _ <- entitlementsByBank.exists(_.roleName == CanReadDynamicResourceDocsAtOneBank.toString()) match {
-// case true =>
-// // Already has entitlement
-// Future(())
-// case false =>
-// Future(Entitlement.entitlement.vend.addEntitlement(postJson.bank_id, cc.userId, CanReadDynamicResourceDocsAtOneBank.toString()))
-// }
-// } yield {
-// (JSONFactory600.createBankJSON600(success), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getProviders,
-// implementedInApiVersion,
-// nameOf(getProviders),
-// "GET",
-// "/providers",
-// "Get Providers",
-// s"""Get the list of authentication providers that have been used to create users on this OBP instance.
-// |
-// |This endpoint returns a distinct list of provider values from the resource_user table.
-// |
-// |Providers may include:
-// |* Local OBP provider (e.g., "http://127.0.0.1:8080")
-// |* OAuth 2.0 / OpenID Connect providers (e.g., "google.com", "microsoft.com")
-// |* Custom authentication providers
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.createProvidersJson(List("http://127.0.0.1:8080", "OBP", "google.com")),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagUser),
-// None
-// )
-//
-// lazy val getProviders: OBPEndpoint = {
-// case "providers" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// providers <- Future { code.model.dataAccess.ResourceUser.getDistinctProviders }
-// } yield {
-// (JSONFactory600.createProvidersJson(providers), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConnectorMethodNames,
-// implementedInApiVersion,
-// nameOf(getConnectorMethodNames),
-// "GET",
-// "/system/connector-method-names",
-// "Get Connector Method Names",
-// s"""Get the list of all available connector method names.
-// |
-// |These are the method names that can be used in Method Routing configuration.
-// |
-// |## Data Source
-// |
-// |The data comes from **scanning the actual Scala connector code at runtime** using reflection, NOT from a database or configuration file.
-// |
-// |The endpoint:
-// |1. Reads the connector name from props (e.g., `connector=mapped`)
-// |2. Gets the connector instance (e.g., LocalMappedConnector, KafkaConnector, StarConnector)
-// |3. Uses Scala reflection to scan all public methods that override the base Connector trait
-// |4. Filters for valid connector methods (public, has parameters, overrides base trait)
-// |5. Returns the method names as a sorted list
-// |
-// |## Which Connector?
-// |
-// |Depends on your `connector` property:
-// |* `connector=mapped` → Returns methods from LocalMappedConnector
-// |* `connector=kafka_vSept2018` → Returns methods from KafkaConnector
-// |* `connector=star` → Returns methods from StarConnector
-// |* `connector=rest_vMar2019` → Returns methods from RestConnector
-// |
-// |## When Does It Change?
-// |
-// |The list only changes when:
-// |* Code is deployed with new/modified connector methods
-// |* The `connector` property is changed to point to a different connector
-// |
-// |## Performance
-// |
-// |This endpoint uses caching (default: 1 hour) because Scala reflection is expensive.
-// |Configure via: `getConnectorMethodNames.cache.ttl.seconds=3600`
-// |
-// |## Use Case
-// |
-// |Use this endpoint to discover which connector methods are available when configuring Method Routing.
-// |These method names are different from API endpoint operation IDs (which you get from /resource-docs).
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanGetSystemConnectorMethodNames entitlement is required.
-// |
-// """.stripMargin,
-// EmptyBody,
-// ConnectorMethodNamesJsonV600(List("getBank", "getBanks", "getUser", "getAccount", "makePayment", "getTransactions")),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagConnectorMethod, apiTagSystem, apiTagMethodRouting, apiTagApi),
-// Some(List(canGetSystemConnectorMethodNames))
-// )
-//
-// lazy val getConnectorMethodNames: OBPEndpoint = {
-// case "system" :: "connector-method-names" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// // Fetch connector method names with caching
-// methodNames <- Future {
-// /**
-// * Connector methods rarely change (only on deployment), so we cache for a long time.
-// */
-// val cacheKey = "getConnectorMethodNames"
-// val cacheTTL = APIUtil.getPropsAsIntValue("getConnectorMethodNames.cache.ttl.seconds", 3600)
-// Caching.memoizeSyncWithProvider(Some(cacheKey))(cacheTTL.seconds) {
-// val connectorName = APIUtil.getPropsValue("connector", "mapped")
-// val connector = code.bankconnectors.Connector.getConnectorInstance(connectorName)
-// connector.callableMethods.keys.toList
-// }
-// }
-// } yield {
-// (JSONFactory600.createConnectorMethodNamesJson(methodNames), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConnectors,
-// implementedInApiVersion,
-// nameOf(getConnectors),
-// "GET",
-// "/system/connectors",
-// "Get Connectors",
-// s"""Get the list of connectors and their availability for method routing.
-// |
-// |Returns a sorted list of all connectors with their availability status for use in Method Routing.
-// |
-// |## Response Fields
-// |
-// |* **connector_name** - The name of the connector
-// |* **is_available_in_method_routing** - Whether this connector can be used in Method Routing configuration.
-// | This depends on the `connector` and `starConnector_supported_types` props settings.
-// |
-// |## Available Connectors
-// |
-// |The OBP-API supports multiple connectors for accessing banking data:
-// |
-// |* **mapped** - Local database connector using Lift Mapper ORM
-// |* **akka_vDec2018** - Akka-based connector for remote banking systems
-// |* **rest_vMar2019** - REST connector for external APIs
-// |* **stored_procedure_vDec2019** - Stored procedure connector for database-native operations
-// |* **rabbitmq_vOct2024** - RabbitMQ message queue connector
-// |* **cardano_vJun2025** - Cardano blockchain connector
-// |* **ethereum_vSept2025** - Ethereum blockchain connector
-// |* **star** - Star connector (special routing connector)
-// |* **proxy** - Proxy connector (for testing)
-// |* **internal** - Internal dynamic connector
-// |
-// |## Use Case
-// |
-// |Use this endpoint to discover which connectors are available when configuring Method Routing.
-// |A connector is available for method routing if it matches the `connector` prop setting,
-// |or if `connector=star` and the connector is listed in `starConnector_supported_types`.
-// |
-// |Authentication is Optional.
-// |
-// """.stripMargin,
-// EmptyBody,
-// ConnectorsJsonV600(List(
-// ConnectorInfoJsonV600("mapped", true),
-// ConnectorInfoJsonV600("akka_vDec2018", false),
-// ConnectorInfoJsonV600("rest_vMar2019", true),
-// ConnectorInfoJsonV600("stored_procedure_vDec2019", false)
-// )),
-// List(
-// UnknownError
-// ),
-// List(apiTagConnector, apiTagSystem, apiTagApi),
-// None
-// )
-//
-// lazy val getConnectors: OBPEndpoint = {
-// case "system" :: "connectors" :: Nil JsonGet _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// } yield {
-// // Get the connector names from the Connector object's nameToConnector map
-// // Also include "star" which is handled separately in getConnectorInstance
-// val connectorNames = code.bankconnectors.Connector.nameToConnector.keys.toList :+ "star"
-// val connectorInfos = connectorNames.map { name =>
-// ConnectorInfoJsonV600(
-// connector_name = name,
-// is_available_in_method_routing = NewStyle.function.getConnectorByName(name).isDefined
-// )
-// }
-// (JSONFactory600.createConnectorsJson(connectorInfos), HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getTopAPIs,
-// implementedInApiVersion,
-// nameOf(getTopAPIs),
-// "GET",
-// "/management/metrics/top-apis",
-// "Get Top APIs",
-// s"""Get metrics about the most popular APIs. e.g.: total count, response time (in ms), etc.
-// |
-// |This v6.0.0 version includes the **operation_id** field which uniquely identifies each API endpoint
-// |across different API standards (OBP, Berlin Group, UK Open Banking, etc.).
-// |
-// |Should be able to filter on the following fields:
-// |
-// |eg: /management/metrics/top-apis?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5
-// |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount
-// |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions
-// |&verb=GET&anon=false&app_name=MapperPostman
-// |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |1 from_date (defaults to one year ago): eg:from_date=$epochTimeString
-// |
-// |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString
-// |
-// |3 consumer_id (if null ignore)
-// |
-// |4 user_id (if null ignore)
-// |
-// |5 anon (if null ignore) only support two values: true (return where user_id is null) or false (return where user_id is not null)
-// |
-// |6 url (if null ignore), note: can not contain '&'.
-// |
-// |7 app_name (if null ignore)
-// |
-// |8 implemented_by_partial_function (if null ignore)
-// |
-// |9 implemented_in_version (if null ignore)
-// |
-// |10 verb (if null ignore)
-// |
-// |11 correlation_id (if null ignore)
-// |
-// |12 duration (if null ignore) non digit chars will be silently omitted
-// |
-// |13 exclude_app_names (if null ignore). eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |14 exclude_url_patterns (if null ignore). You can design your own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%
-// |
-// |15 exclude_implemented_by_partial_functions (if null ignore). eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |CanReadMetrics entitlement is required.
-// |
-// """.stripMargin,
-// EmptyBody,
-// TopApisJsonV600(List(
-// TopApiJsonV600(1000, "getBanks", "v4.0.0", "OBPv4.0.0-getBanks"),
-// TopApiJsonV600(500, "getBank", "v4.0.0", "OBPv4.0.0-getBank"),
-// TopApiJsonV600(250, "getAccountList", "v1.3", "BGv1.3-getAccountList")
-// )),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidFilterParameterFormat,
-// GetTopApisError,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canReadMetrics))
-// )
-//
-// lazy val getTopAPIs: OBPEndpoint = {
-// case "management" :: "metrics" :: "top-apis" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// topApis <- APIMetrics.apiMetrics.vend.getTopApisFuture(obpQueryParams) map {
-// unboxFullOrFail(_, callContext, GetTopApisError)
-// }
-// } yield {
-// // Build lookup map from partialFunctionName -> operationId
-// // This handles OBP, Berlin Group, UK Open Banking, and other standards correctly
-// val allDocs = APIUtil.getAllResourceDocs
-// val lookupMap: Map[String, String] = allDocs.map { doc =>
-// doc.partialFunctionName -> doc.operationId
-// }.toMap
-//
-// // Convert TopApi to TopApiJsonV600 with operation_id
-// val topApisWithOperationId = topApis.map { api =>
-// val operationId = lookupMap.getOrElse(
-// api.ImplementedByPartialFunction,
-// scala.util.Try(APIUtil.buildOperationId(ApiVersionUtils.valueOf(api.implementedInVersion), api.ImplementedByPartialFunction))
-// .getOrElse(s"${api.implementedInVersion}-${api.ImplementedByPartialFunction}")
-// )
-// TopApiJsonV600(
-// count = api.count,
-// implemented_by_partial_function = api.ImplementedByPartialFunction,
-// implemented_in_version = api.implementedInVersion,
-// operation_id = operationId
-// )
-// }
-// (JSONFactory600.createTopApisJsonV600(topApisWithOperationId), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getScannedApiVersions,
-// implementedInApiVersion,
-// nameOf(getScannedApiVersions),
-// "GET",
-// "/api/versions",
-// "Get Scanned API Versions",
-// s"""Get all scanned API versions available in this codebase.
-// |
-// |This endpoint returns all API versions that have been discovered/scanned, along with their active status.
-// |
-// |**Response Fields:**
-// |
-// |* `url_prefix`: The URL prefix for the version (e.g., "obp", "berlin-group", "open-banking")
-// |* `api_standard`: The API standard name (e.g., "OBP", "BG", "UK", "STET")
-// |* `api_short_version`: The version number (e.g., "v4.0.0", "v1.3")
-// |* `fully_qualified_version`: The fully qualified version combining standard and version (e.g., "OBPv4.0.0", "BGv1.3")
-// |* `is_active`: Boolean indicating if the version is currently enabled and accessible
-// |
-// |**Active Status:**
-// |
-// |* `is_active=true`: Version is enabled and can be accessed via its URL prefix
-// |* `is_active=false`: Version is scanned but disabled (via `api_disabled_versions` props)
-// |
-// |**Use Cases:**
-// |
-// |* Discover what API versions are available in the codebase
-// |* Check which versions are currently enabled
-// |* Verify that disabled versions configuration is working correctly
-// |* API documentation and discovery
-// |
-// |**Note:** This differs from v4.0.0's `/api/versions` endpoint which shows all scanned versions without is_active status.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "scanned_api_versions",
-// List(
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_2_1.toString, fully_qualified_version = ApiVersion.v1_2_1.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_3_0.toString, fully_qualified_version = ApiVersion.v1_3_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_4_0.toString, fully_qualified_version = ApiVersion.v1_4_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_0_0.toString, fully_qualified_version = ApiVersion.v2_0_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_1_0.toString, fully_qualified_version = ApiVersion.v2_1_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_2_0.toString, fully_qualified_version = ApiVersion.v2_2_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v3_0_0.toString, fully_qualified_version = ApiVersion.v3_0_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v3_1_0.toString, fully_qualified_version = ApiVersion.v3_1_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v4_0_0.toString, fully_qualified_version = ApiVersion.v4_0_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v5_0_0.toString, fully_qualified_version = ApiVersion.v5_0_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v5_1_0.toString, fully_qualified_version = ApiVersion.v5_1_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v6_0_0.toString, fully_qualified_version = ApiVersion.v6_0_0.fullyQualifiedVersion, is_active = true),
-// ScannedApiVersionJsonV600(url_prefix = "berlin-group", api_standard = "BG", api_short_version = "v1.3", fully_qualified_version = "BGv1.3", is_active = false)
-// )
-// ),
-// List(
-// UnknownError
-// ),
-// List(apiTagDocumentation, apiTagApi),
-// Some(Nil)
-// )
-//
-// lazy val getScannedApiVersions: OBPEndpoint = {
-// case "api" :: "versions" :: Nil JsonGet _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// Future {
-// val versions: List[ScannedApiVersionJsonV600] =
-// ApiVersion.allScannedApiVersion.asScala.toList
-// .filter(version => version.urlPrefix.trim.nonEmpty)
-// .map { version =>
-// ScannedApiVersionJsonV600(
-// url_prefix = version.urlPrefix,
-// api_standard = version.apiStandard,
-// api_short_version = version.apiShortVersion,
-// fully_qualified_version = version.fullyQualifiedVersion,
-// is_active = versionIsAllowed(version)
-// )
-// }
-// (
-// ListResult("scanned_api_versions", versions),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomer,
-// implementedInApiVersion,
-// nameOf(createCustomer),
-// "POST",
-// "/banks/BANK_ID/customers",
-// "Create Customer",
-// s"""
-// |The Customer resource stores the customer number, legal name, email, phone number, date of birth, relationship status,
-// |education attained, a url for a profile image, KYC status, credit rating, credit limit, and other customer information.
-// |
-// |**Required Fields:**
-// |- legal_name: The customer's full legal name
-// |- mobile_phone_number: The customer's mobile phone number
-// |
-// |**Optional Fields:**
-// |- customer_number: If not provided, a random number will be generated
-// |- email: Customer's email address
-// |- face_image: Customer's face image (url and date)
-// |- date_of_birth: Customer's date of birth in YYYY-MM-DD format
-// |- relationship_status: Customer's relationship status
-// |- dependants: Number of dependants (must match the length of dob_of_dependants array)
-// |- dob_of_dependants: Array of dependant birth dates in YYYY-MM-DD format
-// |- credit_rating: Customer's credit rating (rating and source)
-// |- credit_limit: Customer's credit limit (currency and amount)
-// |- highest_education_attained: Customer's highest education level
-// |- employment_status: Customer's employment status
-// |- kyc_status: Know Your Customer verification status (true/false). Default: false
-// |- last_ok_date: Last verification date
-// |- title: Customer's title (e.g., Mr., Mrs., Dr.)
-// |- branch_id: Associated branch identifier
-// |- name_suffix: Customer's name suffix (e.g., Jr., Sr.)
-// |- customer_type: Type of customer - INDIVIDUAL (default), CORPORATE, or SUBSIDIARY
-// |- parent_customer_id: For SUBSIDIARY customers, the customer_id of the parent CORPORATE customer
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants must be provided in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |The dates are strictly validated and must be valid calendar dates.
-// |Dates are stored with time set to midnight (00:00:00) UTC for consistency.
-// |
-// |**Validations:**
-// |- customer_number cannot contain `::::` characters
-// |- customer_number must be unique for the bank
-// |- The number of dependants must equal the length of the dob_of_dependants array
-// |- date_of_birth must be in valid YYYY-MM-DD format if provided
-// |- Each date in dob_of_dependants must be in valid YYYY-MM-DD format
-// |
-// |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// postCustomerJsonV600,
-// customerJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// InvalidJsonContent,
-// InvalidDateFormat,
-// InvalidCustomerType,
-// ParentCustomerNotFound,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateConsumerError,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagPerson),
-// Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))
-// )
-// lazy val createCustomer : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV600 ", 400, cc.callContext) {
-// json.extract[PostCustomerJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants.getOrElse(0)}) not equal the length(${postedData.dob_of_dependants.getOrElse(Nil).length }) of dob_of_dependants array", 400, cc.callContext) {
-// postedData.dependants.getOrElse(0) == postedData.dob_of_dependants.getOrElse(Nil).length
-// }
-//
-// // Validate and parse date_of_birth (YYYY-MM-DD format)
-// dateOfBirth <- Future {
-// postedData.date_of_birth.map { dateStr =>
-// try {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(dateStr)
-// } catch {
-// case _: Exception =>
-// throw new Exception(s"$InvalidJsonFormat date_of_birth must be in YYYY-MM-DD format (e.g., 1990-05-15), got: $dateStr")
-// }
-// }.orNull
-// }
-//
-// // Validate and parse dob_of_dependants (YYYY-MM-DD format)
-// dobOfDependants <- Future {
-// postedData.dob_of_dependants.getOrElse(Nil).map { dateStr =>
-// try {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(dateStr)
-// } catch {
-// case _: Exception =>
-// throw new Exception(s"$InvalidJsonFormat dob_of_dependants must contain dates in YYYY-MM-DD format (e.g., 2010-03-20), got: $dateStr")
-// }
-// }
-// }
-//
-// customerNumber = postedData.customer_number.getOrElse(Random.nextInt(Integer.MAX_VALUE).toString)
-//
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat customer_number can not contain `::::` characters", cc=cc.callContext) {
-// !`checkIfContains::::` (customerNumber)
-// }
-// (_, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, customerNumber, cc.callContext)
-//
-// customerType = postedData.customer_type.getOrElse("INDIVIDUAL")
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomerType, 400, callContext) {
-// List("INDIVIDUAL", "CORPORATE", "SUBSIDIARY").contains(customerType)
-// }
-//
-// parentCustomerIdValue = postedData.parent_customer_id.getOrElse("")
-// _ <- if (parentCustomerIdValue.nonEmpty) {
-// NewStyle.function.getCustomerByCustomerId(parentCustomerIdValue, callContext).map(_ => ())
-// } else {
-// Future.successful(())
-// }
-//
-// (customer, callContext) <- NewStyle.function.createCustomerC2(
-// bankId,
-// postedData.legal_name,
-// customerNumber,
-// postedData.mobile_phone_number,
-// postedData.email.getOrElse(""),
-// CustomerFaceImage(
-// postedData.face_image.map(_.date).getOrElse(null),
-// postedData.face_image.map(_.url).getOrElse("")
-// ),
-// dateOfBirth,
-// postedData.relationship_status.getOrElse(""),
-// postedData.dependants.getOrElse(0),
-// dobOfDependants,
-// postedData.highest_education_attained.getOrElse(""),
-// postedData.employment_status.getOrElse(""),
-// postedData.kyc_status.getOrElse(false),
-// postedData.last_ok_date.getOrElse(null),
-// postedData.credit_rating.map(i => CreditRating(i.rating, i.source)),
-// postedData.credit_limit.map(i => CreditLimit(i.currency, i.amount)),
-// postedData.title.getOrElse(""),
-// postedData.branch_id.getOrElse(""),
-// postedData.name_suffix.getOrElse(""),
-// customerType,
-// parentCustomerIdValue,
-// callContext,
-// )
-// } yield {
-// (JSONFactory600.createCustomerJson(customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerChildren,
-// implementedInApiVersion,
-// nameOf(getCustomerChildren),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/children",
-// "Get Customer Children",
-// s"""Get the child (subsidiary) customers of a parent customer.
-// |
-// |Returns a list of customers whose parent_customer_id matches the specified CUSTOMER_ID.
-// |This is useful for corporate banking where a corporate customer may have subsidiary customers.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getCustomerChildren: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "children" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (children, callContext) <- NewStyle.function.getCustomersByParentCustomerId(bankId, customerId, callContext)
-// } yield {
-// (JSONFactory600.createCustomersJson(children), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersAtAllBanks,
-// implementedInApiVersion,
-// nameOf(getCustomersAtAllBanks),
-// "GET",
-// "/customers",
-// "Get Customers at All Banks",
-// s"""Get Customers at All Banks.
-// |
-// |Returns a list of all customers across all banks.
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |
-// |**Query Parameters:**
-// |- limit: Maximum number of customers to return (optional)
-// |- offset: Number of customers to skip for pagination (optional)
-// |- sort_direction: Sort direction - ASC or DESC (optional)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersAtAllBanks))
-// )
-//
-// lazy val getCustomersAtAllBanks : OBPEndpoint = {
-// case "customers" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
-// (customers, callContext) <- NewStyle.function.getCustomersAtAllBanks(callContext, requestParams)
-// } yield {
-// (JSONFactory600.createCustomersJson(customers.sortBy(_.bankId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersByLegalName,
-// implementedInApiVersion,
-// nameOf(getCustomersByLegalName),
-// "POST",
-// "/banks/BANK_ID/customers/legal-name",
-// "Get Customers by Legal Name",
-// s"""Gets the Customers specified by Legal Name.
-// |
-// |Returns a list of customers that match the provided legal name.
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// PostCustomerLegalNameJsonV510(legal_name = "John Smith"),
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersByLegalName: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "legal-name" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (bank, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerLegalNameJsonV510 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerLegalNameJsonV510]
-// }
-// (customers, callContext) <- NewStyle.function.getCustomersByCustomerLegalName(bank.bankId, postedData.legal_name, callContext)
-// } yield {
-// (JSONFactory600.createCustomersJson(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomersAtOneBank,
-// implementedInApiVersion,
-// nameOf(getCustomersAtOneBank),
-// "GET",
-// "/banks/BANK_ID/customers",
-// "Get Customers at Bank",
-// s"""Get Customers at Bank.
-// |
-// |Returns a list of all customers at the specified bank.
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |
-// |**Query Parameters:**
-// |- limit: Maximum number of customers to return (optional)
-// |- offset: Number of customers to skip for pagination (optional)
-// |- sort_direction: Sort direction - ASC or DESC (optional)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagUser),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomersAtOneBank : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
-// customers <- NewStyle.function.getCustomers(bankId, callContext, requestParams)
-// } yield {
-// (JSONFactory600.createCustomersJson(customers.sortBy(_.bankId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCustomerByCustomerId),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID",
-// "Get Customer by CUSTOMER_ID",
-// s"""Gets the Customer specified by CUSTOMER_ID.
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// customerWithAttributesJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank)))
-//
-// lazy val getCustomerByCustomerId : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory600.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerByCustomerNumber,
-// implementedInApiVersion,
-// nameOf(getCustomerByCustomerNumber),
-// "POST",
-// "/banks/BANK_ID/customers/customer-number",
-// "Get Customer by CUSTOMER_NUMBER",
-// s"""Gets the Customer specified by CUSTOMER_NUMBER.
-// |
-// |**Date Format:**
-// |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., "1990-05-15", "2010-03-20").
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// postCustomerNumberJsonV310,
-// customerWithAttributesJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserCustomerLinksNotFoundForUser,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc),
-// Some(List(canGetCustomersAtOneBank))
-// )
-//
-// lazy val getCustomerByCustomerNumber : OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: "customer-number" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (bank, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerNumberJsonV310 "
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[PostCustomerNumberJsonV310]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerNumber(postedData.customer_number, bank.bankId, callContext)
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customer.customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory600.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Retail Customer Endpoints
-//
-// staticResourceDocs += ResourceDoc(
-// createRetailCustomer,
-// implementedInApiVersion,
-// nameOf(createRetailCustomer),
-// "POST",
-// "/banks/BANK_ID/retail-customers",
-// "Create Retail Customer",
-// s"""Create a retail (individual) customer.
-// |
-// |This endpoint is specifically for creating individual/retail customers.
-// |The customer_type will be automatically set to INDIVIDUAL.
-// |
-// |**Required Fields:**
-// |- legal_name: The customer's full legal name
-// |- mobile_phone_number: The customer's mobile phone number
-// |
-// |**Optional Fields:**
-// |- customer_number: If not provided, a random number will be generated
-// |- email, face_image, date_of_birth, relationship_status, dependants, dob_of_dependants
-// |- credit_rating, credit_limit, highest_education_attained, employment_status
-// |- kyc_status, last_ok_date, title, branch_id, name_suffix
-// |
-// |**Date Format:**
-// |date_of_birth and dob_of_dependants must be in ISO 8601 date format: **YYYY-MM-DD**
-// |
-// |**Validations:**
-// |- customer_number cannot contain `::::` characters
-// |- customer_number must be unique for the bank
-// |- The number of dependants must equal the length of the dob_of_dependants array
-// |
-// |Authentication is Required
-// |""",
-// postRetailCustomerJsonV600,
-// customerJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// InvalidJsonContent,
-// InvalidDateFormat,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateConsumerError,
-// UnknownError
-// ),
-// List(apiTagRetailCustomer, apiTagCustomer),
-// Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))
-// )
-// lazy val createRetailCustomer: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "retail-customers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostRetailCustomerJsonV600 ", 400, cc.callContext) {
-// json.extract[PostRetailCustomerJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants.getOrElse(0)}) not equal the length(${postedData.dob_of_dependants.getOrElse(Nil).length}) of dob_of_dependants array", 400, cc.callContext) {
-// postedData.dependants.getOrElse(0) == postedData.dob_of_dependants.getOrElse(Nil).length
-// }
-// dateOfBirth <- Future {
-// postedData.date_of_birth.map { dateStr =>
-// try {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(dateStr)
-// } catch {
-// case _: Exception =>
-// throw new Exception(s"$InvalidJsonFormat date_of_birth must be in YYYY-MM-DD format (e.g., 1990-05-15), got: $dateStr")
-// }
-// }.orNull
-// }
-// dobOfDependants <- Future {
-// postedData.dob_of_dependants.getOrElse(Nil).map { dateStr =>
-// try {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(dateStr)
-// } catch {
-// case _: Exception =>
-// throw new Exception(s"$InvalidJsonFormat dob_of_dependants must contain dates in YYYY-MM-DD format (e.g., 2010-03-20), got: $dateStr")
-// }
-// }
-// }
-// customerNumber = postedData.customer_number.getOrElse(Random.nextInt(Integer.MAX_VALUE).toString)
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat customer_number can not contain `::::` characters", cc = cc.callContext) {
-// !`checkIfContains::::` (customerNumber)
-// }
-// (_, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, customerNumber, cc.callContext)
-// (customer, callContext) <- NewStyle.function.createCustomerC2(
-// bankId,
-// postedData.legal_name,
-// customerNumber,
-// postedData.mobile_phone_number,
-// postedData.email.getOrElse(""),
-// CustomerFaceImage(
-// postedData.face_image.map(_.date).getOrElse(null),
-// postedData.face_image.map(_.url).getOrElse("")
-// ),
-// dateOfBirth,
-// postedData.relationship_status.getOrElse(""),
-// postedData.dependants.getOrElse(0),
-// dobOfDependants,
-// postedData.highest_education_attained.getOrElse(""),
-// postedData.employment_status.getOrElse(""),
-// postedData.kyc_status.getOrElse(false),
-// postedData.last_ok_date.getOrElse(null),
-// postedData.credit_rating.map(i => CreditRating(i.rating, i.source)),
-// postedData.credit_limit.map(i => CreditLimit(i.currency, i.amount)),
-// postedData.title.getOrElse(""),
-// postedData.branch_id.getOrElse(""),
-// postedData.name_suffix.getOrElse(""),
-// "INDIVIDUAL",
-// "",
-// callContext,
-// )
-// } yield {
-// (JSONFactory600.createCustomerJson(customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getRetailCustomersAtOneBank,
-// implementedInApiVersion,
-// nameOf(getRetailCustomersAtOneBank),
-// "GET",
-// "/banks/BANK_ID/retail-customers",
-// "Get Retail Customers at Bank",
-// s"""Get Retail (Individual) Customers at Bank.
-// |
-// |Returns a list of customers with customer_type INDIVIDUAL at the specified bank.
-// |
-// |**Date Format:**
-// |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**
-// |
-// |**Query Parameters:**
-// |- limit: Maximum number of customers to return (optional)
-// |- offset: Number of customers to skip for pagination (optional)
-// |- sort_direction: Sort direction - ASC or DESC (optional)
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagRetailCustomer, apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getRetailCustomersAtOneBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "retail-customers" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit", "offset", "sort_direction"), cc.callContext)
-// (customers, callContext) <- NewStyle.function.getCustomersByCustomerTypes(bankId, List("INDIVIDUAL"), callContext, requestParams)
-// } yield {
-// (JSONFactory600.createCustomersJson(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getRetailCustomerByCustomerId,
-// implementedInApiVersion,
-// nameOf(getRetailCustomerByCustomerId),
-// "GET",
-// "/banks/BANK_ID/retail-customers/CUSTOMER_ID",
-// "Get Retail Customer by CUSTOMER_ID",
-// s"""Gets the Retail Customer specified by CUSTOMER_ID.
-// |
-// |Returns 404 if the customer exists but is not of type INDIVIDUAL.
-// |Use the generic /customers/CUSTOMER_ID endpoint for any customer type.
-// |
-// |**Date Format:**
-// |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerWithAttributesJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// CustomerTypeMismatch,
-// UnknownError
-// ),
-// List(apiTagRetailCustomer, apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getRetailCustomerByCustomerId: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "retail-customers" :: customerId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// _ <- Helper.booleanToFuture(failMsg = CustomerTypeMismatch, 404, callContext) {
-// customer.customerType.contains("INDIVIDUAL")
-// }
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory600.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Corporate Customer Endpoints
-//
-// staticResourceDocs += ResourceDoc(
-// createCorporateCustomer,
-// implementedInApiVersion,
-// nameOf(createCorporateCustomer),
-// "POST",
-// "/banks/BANK_ID/corporate-customers",
-// "Create Corporate Customer",
-// s"""Create a corporate customer.
-// |
-// |This endpoint is specifically for creating corporate customers.
-// |Individual-oriented fields (relationship_status, dependants, highest_education_attained, employment_status, name_suffix, date_of_birth, face_image, title) are not available on this endpoint.
-// |
-// |**Required Fields:**
-// |- legal_name: The corporate entity's legal name
-// |- mobile_phone_number: The corporate entity's phone number
-// |
-// |**Optional Fields:**
-// |- customer_number: If not provided, a random number will be generated
-// |- email, credit_rating, credit_limit, kyc_status, last_ok_date, branch_id
-// |- customer_type: CORPORATE (default) or SUBSIDIARY
-// |- parent_customer_id: For SUBSIDIARY customers, the customer_id of the parent customer
-// |
-// |**Validations:**
-// |- customer_number cannot contain `::::` characters
-// |- customer_number must be unique for the bank
-// |- customer_type must be CORPORATE or SUBSIDIARY
-// |- parent_customer_id must reference an existing customer if provided
-// |
-// |Authentication is Required
-// |""",
-// postCorporateCustomerJsonV600,
-// customerJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// InvalidCustomerType,
-// ParentCustomerNotFound,
-// CustomerNumberAlreadyExists,
-// UserNotFoundById,
-// CustomerAlreadyExistsForUser,
-// CreateConsumerError,
-// UnknownError
-// ),
-// List(apiTagCorporateCustomer, apiTagCustomer),
-// Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))
-// )
-// lazy val createCorporateCustomer: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "corporate-customers" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCorporateCustomerJsonV600 ", 400, cc.callContext) {
-// json.extract[PostCorporateCustomerJsonV600]
-// }
-// customerNumber = postedData.customer_number.getOrElse(Random.nextInt(Integer.MAX_VALUE).toString)
-// _ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat customer_number can not contain `::::` characters", cc = cc.callContext) {
-// !`checkIfContains::::` (customerNumber)
-// }
-// (_, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, customerNumber, cc.callContext)
-// customerType = postedData.customer_type.getOrElse("CORPORATE")
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomerType + " For corporate customers, must be CORPORATE or SUBSIDIARY.", 400, callContext) {
-// List("CORPORATE", "SUBSIDIARY").contains(customerType)
-// }
-// parentCustomerIdValue = postedData.parent_customer_id.getOrElse("")
-// _ <- if (parentCustomerIdValue.nonEmpty) {
-// NewStyle.function.getCustomerByCustomerId(parentCustomerIdValue, callContext).map(_ => ())
-// } else {
-// Future.successful(())
-// }
-// (customer, callContext) <- NewStyle.function.createCustomerC2(
-// bankId,
-// postedData.legal_name,
-// customerNumber,
-// postedData.mobile_phone_number,
-// postedData.email.getOrElse(""),
-// CustomerFaceImage(null, ""), // not applicable for corporate
-// null, // date_of_birth - not applicable for corporate
-// "", // relationship_status - not applicable for corporate
-// 0, // dependants - not applicable for corporate
-// Nil, // dob_of_dependants - not applicable for corporate
-// "", // highest_education_attained - not applicable for corporate
-// "", // employment_status - not applicable for corporate
-// postedData.kyc_status.getOrElse(false),
-// postedData.last_ok_date.getOrElse(null),
-// postedData.credit_rating.map(i => CreditRating(i.rating, i.source)),
-// postedData.credit_limit.map(i => CreditLimit(i.currency, i.amount)),
-// "", // title - not applicable for corporate
-// postedData.branch_id.getOrElse(""),
-// "", // name_suffix - not applicable for corporate
-// customerType,
-// parentCustomerIdValue,
-// callContext,
-// )
-// } yield {
-// (JSONFactory600.createCustomerJson(customer), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCorporateCustomersAtOneBank,
-// implementedInApiVersion,
-// nameOf(getCorporateCustomersAtOneBank),
-// "GET",
-// "/banks/BANK_ID/corporate-customers",
-// "Get Corporate Customers at Bank",
-// s"""Get Corporate Customers at Bank.
-// |
-// |Returns a list of customers with customer_type CORPORATE or SUBSIDIARY at the specified bank.
-// |
-// |**Date Format:**
-// |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**
-// |
-// |**Query Parameters:**
-// |- limit: Maximum number of customers to return (optional)
-// |- offset: Number of customers to skip for pagination (optional)
-// |- sort_direction: Sort direction - ASC or DESC (optional)
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagCorporateCustomer, apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getCorporateCustomersAtOneBank: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "corporate-customers" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (requestParams, callContext) <- extractQueryParams(cc.url, List("limit", "offset", "sort_direction"), cc.callContext)
-// (customers, callContext) <- NewStyle.function.getCustomersByCustomerTypes(bankId, List("CORPORATE", "SUBSIDIARY"), callContext, requestParams)
-// } yield {
-// (JSONFactory600.createCustomersJson(customers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCorporateCustomerByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCorporateCustomerByCustomerId),
-// "GET",
-// "/banks/BANK_ID/corporate-customers/CUSTOMER_ID",
-// "Get Corporate Customer by CUSTOMER_ID",
-// s"""Gets the Corporate Customer specified by CUSTOMER_ID.
-// |
-// |Returns 404 if the customer exists but is not of type CORPORATE or SUBSIDIARY.
-// |Use the generic /customers/CUSTOMER_ID endpoint for any customer type.
-// |
-// |**Date Format:**
-// |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerWithAttributesJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// CustomerTypeMismatch,
-// UnknownError
-// ),
-// List(apiTagCorporateCustomer, apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getCorporateCustomerByCustomerId: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "corporate-customers" :: customerId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// _ <- Helper.booleanToFuture(failMsg = CustomerTypeMismatch, 404, callContext) {
-// customer.customerType.exists(ct => List("CORPORATE", "SUBSIDIARY").contains(ct))
-// }
-// (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes(
-// bankId,
-// CustomerId(customerId),
-// callContext: Option[CallContext])
-// } yield {
-// (JSONFactory600.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCorporateCustomerSubsidiaries,
-// implementedInApiVersion,
-// nameOf(getCorporateCustomerSubsidiaries),
-// "GET",
-// "/banks/BANK_ID/corporate-customers/CUSTOMER_ID/subsidiaries",
-// "Get Corporate Customer Subsidiaries",
-// s"""Get the subsidiary customers of a corporate customer.
-// |
-// |Returns a list of customers whose parent_customer_id matches the specified CUSTOMER_ID.
-// |The specified customer must be of type CORPORATE or SUBSIDIARY.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// customerJSONsV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// CustomerTypeMismatch,
-// UnknownError
-// ),
-// List(apiTagCorporateCustomer, apiTagCustomer),
-// Some(List(canGetCustomersAtOneBank))
-// )
-// lazy val getCorporateCustomerSubsidiaries: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "corporate-customers" :: customerId :: "subsidiaries" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- NewStyle.function.getBank(bankId, cc.callContext)
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// _ <- Helper.booleanToFuture(failMsg = CustomerTypeMismatch, 404, callContext) {
-// customer.customerType.exists(ct => List("CORPORATE", "SUBSIDIARY").contains(ct))
-// }
-// (children, callContext) <- NewStyle.function.getCustomersByParentCustomerId(bankId, customerId, callContext)
-// } yield {
-// (JSONFactory600.createCustomersJson(children), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMetrics,
-// implementedInApiVersion,
-// nameOf(getMetrics),
-// "GET",
-// "/management/metrics",
-// "Get Metrics",
-// s"""Get API metrics rows. These are records of each REST API call.
-// |
-// |require CanReadMetrics role
-// |
-// |**NOTE: Automatic from_date Default**
-// |
-// |If you do not provide a `from_date` parameter, this endpoint will automatically set it to:
-// |**now - ${(APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt - 1) / 60} minutes ago**
-// |
-// |This prevents accidentally querying all metrics since Unix Epoch and ensures reasonable response times.
-// |For historical/reporting queries, always explicitly specify your desired `from_date`.
-// |
-// |**IMPORTANT: Smart Caching & Performance**
-// |
-// |This endpoint uses intelligent two-tier caching to optimize performance:
-// |
-// |**Stable Data Cache (Long TTL):**
-// |- Metrics older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600")} seconds (${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} minutes) are considered immutable/stable
-// |- These are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400")} seconds (${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours)
-// |- Used when your query's from_date is older than the stable boundary
-// |
-// |**Recent Data Cache (Short TTL):**
-// |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds
-// |- Used when your query includes recent data or has no from_date
-// |
-// |**STRONGLY RECOMMENDED: Always specify from_date in your queries!**
-// |
-// |**Why from_date matters:**
-// |- Queries WITH from_date older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} mins → cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours (fast!)
-// |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds (slower)
-// |
-// |**Examples:**
-// |- `from_date=2025-01-01T00:00:00.000Z` → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours cache (historical data)
-// |- `from_date=$DateWithMsExampleString` (recent date) → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds cache (recent data)
-// |- No from_date → **Automatically set to ${(APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt - 1) / 60} minutes ago** → Uses ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds cache (recent data)
-// |
-// |For best performance on historical/reporting queries, always include a from_date parameter!
-// |
-// |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics
-// |
-// |You can filter by the following fields by applying url parameters
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
-// |
-// |1 from_date e.g.:from_date=$DateWithMsExampleString
-// | **DEFAULT**: If not provided, automatically set to now - ${(APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt - 1) / 60} minutes (keeps queries in recent data zone)
-// | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!
-// |
-// |2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}
-// |
-// |3 limit (for pagination: defaults to 50) eg:limit=200
-// |
-// |4 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |5 sort_by (defaults to date field) eg: sort_by=date
-// | possible values:
-// | "url",
-// | "date",
-// | "username" (or "user_name" for backward compatibility),
-// | "app_name",
-// | "developer_email",
-// | "implemented_by_partial_function",
-// | "implemented_in_version",
-// | "consumer_id",
-// | "verb"
-// |
-// |6 direction (defaults to date desc) eg: direction=desc
-// |
-// |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78
-// |
-// |Other filters:
-// |
-// |7 consumer_id (if null ignore)
-// |
-// |8 user_id (if null ignore)
-// |
-// |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |10 url (if null ignore), note: can not contain '&'.
-// |
-// |11 app_name (if null ignore)
-// |
-// |12 implemented_by_partial_function (if null ignore),
-// |
-// |13 implemented_in_version (if null ignore)
-// |
-// |14 verb (if null ignore)
-// |
-// |15 correlation_id (if null ignore)
-// |
-// |16 duration (if null ignore) - Returns calls where duration > specified value (in milliseconds). Use this to find slow API calls. eg: duration=5000 returns calls taking more than 5 seconds
-// |
-// """.stripMargin,
-// EmptyBody,
-// metricsJsonV600,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canReadMetrics)))
-//
-// lazy val getMetrics: OBPEndpoint = {
-// case "management" :: "metrics" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canReadMetrics, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// // If from_date is not provided, set it to now - (stable.boundary - 1 second)
-// // This ensures we get recent data with the shorter cache TTL
-// httpParamsWithDefault = {
-// val hasFromDate = httpParams.exists(p => p.name == "from_date" || p.name == "obp_from_date")
-// if (!hasFromDate) {
-// val stableBoundarySeconds = APIUtil.getPropsAsIntValue("MappedMetrics.stable.boundary.seconds", 600)
-// val defaultFromDate = new java.util.Date(System.currentTimeMillis() - ((stableBoundarySeconds - 1) * 1000L))
-// val dateStr = APIUtil.DateWithMsFormat.format(defaultFromDate)
-// HTTPParam("from_date", List(dateStr)) :: httpParams
-// } else {
-// httpParams
-// }
-// }
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParamsWithDefault, callContext)
-// metrics <- Future(APIMetrics.apiMetrics.vend.getAllMetrics(obpQueryParams))
-// _ <- Future {
-// if (metrics.isEmpty) {
-// logger.warn(s"getMetrics returned empty list. Query params: $obpQueryParams, URL: ${cc.url}")
-// }
-// }
-// } yield {
-// // Build lookup map from partialFunctionName -> operationId
-// val allDocs = APIUtil.getAllResourceDocs
-// val lookupMap: Map[String, String] = allDocs.map { doc =>
-// doc.partialFunctionName -> doc.operationId
-// }.toMap
-// (JSONFactory600.createMetricsJsonV600(metrics, lookupMap), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAggregateMetrics,
-// implementedInApiVersion,
-// nameOf(getAggregateMetrics),
-// "GET",
-// "/management/aggregate-metrics",
-// "Get Aggregate Metrics",
-// s"""Returns aggregate metrics on api usage eg. total count, response time (in ms), etc.
-// |
-// |require CanReadAggregateMetrics role
-// |
-// |**NOTE: Automatic from_date Default**
-// |
-// |If you do not provide a `from_date` parameter, this endpoint will automatically set it to:
-// |**now - ${(APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt - 1) / 60} minutes ago**
-// |
-// |This prevents accidentally querying all metrics since Unix Epoch and ensures reasonable response times.
-// |For historical/reporting queries, always explicitly specify your desired `from_date`.
-// |
-// |**IMPORTANT: Smart Caching & Performance**
-// |
-// |This endpoint uses intelligent two-tier caching to optimize performance:
-// |
-// |**Stable Data Cache (Long TTL):**
-// |- Metrics older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600")} seconds (${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} minutes) are considered immutable/stable
-// |- These are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400")} seconds (${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours)
-// |- Used when your query's from_date is older than the stable boundary
-// |
-// |**Recent Data Cache (Short TTL):**
-// |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds
-// |- Used when your query includes recent data or has no from_date
-// |
-// |**Why from_date matters:**
-// |- Queries WITH from_date older than ${APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt / 60} mins → cached for ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getStableMetrics", "86400").toInt / 3600} hours (fast!)
-// |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue("MappedMetrics.cache.ttl.seconds.getAllMetrics", "7")} seconds (slower)
-// |
-// |Should be able to filter on the following fields
-// |
-// |eg: /management/aggregate-metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&consumer_id=5
-// |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount
-// |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions
-// |&verb=GET&anon=false&app_name=MapperPostman
-// |&include_app_names=API-EXPLORER,API-Manager,SOFI,null&http_status_code=200
-// |
-// |**IMPORTANT: v6.0.0+ Breaking Change**
-// |
-// |This version does NOT support the old `exclude_*` parameters:
-// |- `exclude_app_names` - NOT supported (returns error)
-// |- `exclude_url_patterns` - NOT supported (returns error)
-// |- `exclude_implemented_by_partial_functions` - NOT supported (returns error)
-// |
-// |Use `include_*` parameters instead (all optional):
-// |- `include_app_names` - Optional - include only these apps
-// |- `include_url_patterns` - Optional - include only URLs matching these patterns
-// |- `include_implemented_by_partial_functions` - Optional - include only these functions
-// |
-// |1 from_date e.g.:from_date=$DateWithMsExampleString
-// | **DEFAULT**: If not provided, automatically set to now - ${(APIUtil.getPropsValue("MappedMetrics.stable.boundary.seconds", "600").toInt - 1) / 60} minutes (keeps queries in recent data zone)
-// | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!
-// |
-// |2 to_date (defaults to the current date) eg:to_date=$DateWithMsExampleString
-// |
-// |3 consumer_id (if null ignore)
-// |
-// |4 user_id (if null ignore)
-// |
-// |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)
-// |
-// |6 url (if null ignore), note: can not contain '&'.
-// |
-// |7 app_name (if null ignore)
-// |
-// |8 implemented_by_partial_function (if null ignore)
-// |
-// |9 implemented_in_version (if null ignore)
-// |
-// |10 verb (if null ignore)
-// |
-// |11 correlation_id (if null ignore)
-// |
-// |12 include_app_names (if null ignore).eg: &include_app_names=API-EXPLORER,API-Manager,SOFI,null
-// |
-// |13 include_url_patterns (if null ignore).you can design you own SQL LIKE pattern. eg: &include_url_patterns=%management/metrics%,%management/aggregate-metrics%
-// |
-// |14 include_implemented_by_partial_functions (if null ignore).eg: &include_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics
-// |
-// |15 http_status_code (if null ignore) - Filter by HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors
-// |
-// """.stripMargin,
-// EmptyBody,
-// aggregateMetricsJSONV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagAggregateMetrics),
-// Some(List(canReadAggregateMetrics)))
-//
-// lazy val getAggregateMetrics: OBPEndpoint = {
-// case "management" :: "aggregate-metrics" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canReadAggregateMetrics, callContext)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// // Reject old exclude_* parameters in v6.0.0+
-// _ <- Future {
-// val excludeParams = httpParams.filter(p =>
-// p.name == "exclude_app_names" ||
-// p.name == "exclude_url_patterns" ||
-// p.name == "exclude_implemented_by_partial_functions"
-// )
-// if (excludeParams.nonEmpty) {
-// val paramNames = excludeParams.map(_.name).mkString(", ")
-// throw new Exception(s"${ErrorMessages.ExcludeParametersNotSupported} Parameters found: [$paramNames]")
-// }
-// }
-// // If from_date is not provided, set it to now - (stable.boundary - 1 second)
-// // This ensures we get recent data with the shorter cache TTL
-// httpParamsWithDefault = {
-// val hasFromDate = httpParams.exists(p => p.name == "from_date" || p.name == "obp_from_date")
-// if (!hasFromDate) {
-// val stableBoundarySeconds = APIUtil.getPropsAsIntValue("MappedMetrics.stable.boundary.seconds", 600)
-// val defaultFromDate = new java.util.Date(System.currentTimeMillis() - ((stableBoundarySeconds - 1) * 1000L))
-// val dateStr = APIUtil.DateWithMsFormat.format(defaultFromDate)
-// HTTPParam("from_date", List(dateStr)) :: httpParams
-// } else {
-// httpParams
-// }
-// }
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParamsWithDefault, callContext)
-// aggregateMetrics <- APIMetrics.apiMetrics.vend.getAllAggregateMetricsFuture(obpQueryParams, true) map {
-// x => unboxFullOrFail(x, callContext, GetAggregateMetricsError)
-// }
-// _ <- Future {
-// if (aggregateMetrics.isEmpty) {
-// logger.warn(s"getAggregateMetrics returned empty list. Query params: $obpQueryParams, URL: ${cc.url}")
-// }
-// }
-// } yield {
-// (createAggregateMetricJson(aggregateMetrics), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// directLoginEndpoint,
-// implementedInApiVersion,
-// nameOf(directLoginEndpoint),
-// "POST",
-// "/my/logins/direct",
-// "Direct Login",
-// s"""DirectLogin is a simple authentication flow. You POST your credentials (username, password, and consumer key)
-// |to the DirectLogin endpoint and receive a token in return.
-// |
-// |This is an alias to the DirectLogin endpoint that includes the standard API versioning prefix.
-// |
-// |This endpoint requires the following header:
-// |
-// | DirectLogin: username=YOUR_USERNAME, password=YOUR_PASSWORD, consumer_key=YOUR_CONSUMER_KEY
-// |
-// |Note: You can also use the Authorization header (Authorization: DirectLogin username=...) but the DirectLogin header is preferred.
-// |
-// |The token returned can then be used in subsequent API calls using the header:
-// |
-// | DirectLogin: token=YOUR_TOKEN
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.createTokenJSON("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJpYXQiOjE0NTU4OTQyNzYsImV4cCI6MTQ1NTg5Nzg3NiwiYXVkIjoib2JwLWFwaSIsInN1YiI6IjA2Zjc0YjUwLTA5OGYtNDYwNi1hOGNjLTBjNDc5MjAyNmI5ZCIsImNvbnN1bWVyX2tleSI6IjYwNGY3ZTAyNGQ5MWU2MzMwNGMzOGM0YzRmZjc0MjMwZGU5NDk4NTEwNjgxZWNjM2Q5MzViNWQ5MGEwOTI3ODciLCJyb2xlIjoiY2FuX2FjY2Vzc19hcGkifQ.f8xHvXP5fDxo5-LlfTj1OQS9oqHNZfFd7N-WkV2o4Cc"),
-// List(
-// InvalidDirectLoginParameters,
-// InvalidLoginCredentials,
-// InvalidConsumerCredentials,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List()))
-//
-//
-// lazy val directLoginEndpoint: OBPEndpoint = {
-// case "my" :: "logins" :: "direct" :: Nil JsonPost _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (httpCode: Int, message: String, userId: Long) <- DirectLogin.createTokenFuture(DirectLogin.getAllParameters)
-// _ <- Future { DirectLogin.grantEntitlementsToUseDynamicEndpointsInSpacesInDirectLogin(userId) }
-// } yield {
-// if (httpCode == 200) {
-// (JSONFactory600.createTokenJSON(message), HttpCode.`201`(cc.callContext))
-// } else {
-// unboxFullOrFail(Empty, None, message, httpCode)
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// validateUserEmail,
-// implementedInApiVersion,
-// nameOf(validateUserEmail),
-// "POST",
-// "/users/email-validation",
-// "Validate User Email",
-// s"""Validate a user's email address using the JWT token sent via email.
-// |
-// |This is a self-service endpoint for users to confirm their email address as part of the sign-up process.
-// |
-// |When a user registers and email validation is enabled (authUser.skipEmailValidation=false),
-// |they receive an email containing a validation link with a signed JWT token.
-// |The user (or a client application) then calls this endpoint with that token to complete validation.
-// |
-// |This endpoint:
-// |- Verifies the JWT signature and checks expiry
-// |- Extracts the unique ID from the JWT subject
-// |- Sets the user's validated status to true
-// |- Resets the unique ID token (invalidating the link)
-// |- Grants default entitlements to the user
-// |
-// |**Important: This is a single-use token.** Once the email is validated, the token is invalidated.
-// |Any subsequent attempts to use the same token will return a 404 error (UserNotFoundByToken or UserAlreadyValidated).
-// |
-// |The token is a signed JWT with a configurable expiry (default: 1440 minutes / 24 hours).
-// |The server-side expiry can be configured with the `email_validation_token_expiry_minutes` property.
-// |
-// |For administrative validation (without an email token), see the Validate a User endpoint (PUT /management/users/USER_ID).
-// |
-// |${userAuthenticationMessage(false)}
-// |
-// |""".stripMargin,
-// JSONFactory600.ValidateUserEmailJsonV600(
-// token = "eyJhbGciOiJIUzI1NiJ9..."
-// ),
-// JSONFactory600.ValidateUserEmailResponseJsonV600(
-// user_id = "5995d6a2-01b3-423c-a173-5481df49bdaf",
-// email = "user@example.com",
-// username = "username",
-// provider = "https://localhost:8080",
-// validated = true,
-// message = "Email validated successfully"
-// ),
-// List(
-// InvalidJsonFormat,
-// UserNotFoundByToken,
-// UserAlreadyValidated,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List())
-// )
-//
-// lazy val validateUserEmail: OBPEndpoint = {
-// case "users" :: "email-validation" :: Nil JsonPost json -> _ =>
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ValidateUserEmailJsonV600 ", 400, cc.callContext) {
-// json.extract[JSONFactory600.ValidateUserEmailJsonV600]
-// }
-// token = postedData.token.trim
-// _ <- Helper.booleanToFuture(s"$InvalidJsonFormat Token cannot be empty", cc = cc.callContext) {
-// token.nonEmpty
-// }
-// // Verify JWT signature and extract uniqueId from subject
-// uniqueId <- NewStyle.function.tryons(
-// s"$UserNotFoundByToken Invalid or expired validation token",
-// 404,
-// cc.callContext
-// ) {
-// val signedJWT = com.nimbusds.jwt.SignedJWT.parse(token)
-// val expiration = signedJWT.getJWTClaimsSet.getExpirationTime
-// if (expiration == null || expiration.before(new java.util.Date())) {
-// throw new Exception("Token has expired")
-// }
-// if (!CertificateUtil.verifywtWithHmacProtection(token)) {
-// throw new Exception("Invalid token signature")
-// }
-// signedJWT.getJWTClaimsSet.getSubject
-// }
-// // Find user by unique ID from JWT
-// authUser <- Future {
-// code.model.dataAccess.AuthUser.findUserByValidationToken(uniqueId) match {
-// case Full(user) => Full(user)
-// case Empty => Empty
-// case f: net.liftweb.common.Failure => f
-// }
-// }
-// user <- NewStyle.function.tryons(s"$UserNotFoundByToken Invalid or expired validation token", 404, cc.callContext) {
-// authUser.openOrThrowException("User not found")
-// }
-// // Check if user is already validated
-// _ <- Helper.booleanToFuture(s"$UserAlreadyValidated User email is already validated", cc = cc.callContext) {
-// !user.validated.get
-// }
-// // Validate the user and reset the unique ID token
-// validatedUser <- Future {
-// code.model.dataAccess.AuthUser.validateAndResetToken(user)
-// }
-// // Grant default entitlements
-// _ <- Future {
-// code.model.dataAccess.AuthUser.grantDefaultEntitlementsToAuthUser(validatedUser)
-// }
-// } yield {
-// val response = JSONFactory600.ValidateUserEmailResponseJsonV600(
-// user_id = validatedUser.user.obj.map(_.userId).getOrElse(""),
-// email = validatedUser.email.get,
-// username = validatedUser.username.get,
-// provider = validatedUser.provider.get,
-// validated = validatedUser.validated.get,
-// message = "Email validated successfully"
-// )
-// (response, HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-// // ============================================ GROUP MANAGEMENT ============================================
-//
-// staticResourceDocs += ResourceDoc(
-// createGroup,
-// implementedInApiVersion,
-// nameOf(createGroup),
-// "POST",
-// "/management/groups",
-// "Create Group",
-// s"""Create a new group of roles.
-// |
-// |Groups can be either:
-// |- System-level (bank_id = null) - requires CanCreateGroupAtAllBanks role
-// |- Bank-level (bank_id provided) - requires CanCreateGroupAtOneBank role
-// |
-// |A group contains a list of role names that can be assigned together.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// PostGroupJsonV600(
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// group_description = "Standard teller roles for branch operations",
-// list_of_roles = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction"),
-// is_enabled = true
-// ),
-// GroupJsonV600(
-// group_id = "group-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// group_description = "Standard teller roles for branch operations",
-// list_of_roles = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction"),
-// is_enabled = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagGroup),
-// Some(List(canCreateGroupAtAllBanks, canCreateGroupAtOneBank))
-// )
-//
-// lazy val createGroup: OBPEndpoint = {
-// case "management" :: "groups" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostGroupJsonV600", 400, callContext) {
-// json.extract[PostGroupJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"${InvalidJsonFormat} bank_id and group_name cannot be empty", cc = callContext) {
-// postJson.group_name.nonEmpty
-// }
-// _ <- postJson.bank_id match {
-// case Some(bankId) if bankId.nonEmpty =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canCreateGroupAtOneBank :: canCreateGroupAtAllBanks :: Nil, callContext)
-// case _ =>
-// NewStyle.function.hasEntitlement("", u.userId, canCreateGroupAtAllBanks, callContext)
-// }
-// group <- Future {
-// code.group.GroupTrait.group.vend.createGroup(
-// postJson.bank_id.filter(_.nonEmpty),
-// postJson.group_name,
-// postJson.group_description,
-// postJson.list_of_roles,
-// postJson.is_enabled
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot create group", 400)
-// }
-// } yield {
-// val response = GroupJsonV600(
-// group_id = group.groupId,
-// bank_id = group.bankId,
-// group_name = group.groupName,
-// group_description = group.groupDescription,
-// list_of_roles = group.listOfRoles,
-// is_enabled = group.isEnabled
-// )
-// (response, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getGroup,
-// implementedInApiVersion,
-// nameOf(getGroup),
-// "GET",
-// "/management/groups/GROUP_ID",
-// "Get Group",
-// s"""Get a group by its ID.
-// |
-// |Requires either:
-// |- CanGetGroupsAtAllBanks (for any group)
-// |- CanGetGroupsAtOneBank (for groups at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// GroupJsonV600(
-// group_id = "group-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// group_description = "Standard teller roles for branch operations",
-// list_of_roles = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction"),
-// is_enabled = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup),
-// Some(List(canGetGroupsAtAllBanks, canGetGroupsAtOneBank))
-// )
-//
-// lazy val getGroup: OBPEndpoint = {
-// case "management" :: "groups" :: groupId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// group <- Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// _ <- group.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canGetGroupsAtOneBank :: canGetGroupsAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canGetGroupsAtAllBanks, callContext)
-// }
-// } yield {
-// val response = GroupJsonV600(
-// group_id = group.groupId,
-// bank_id = group.bankId,
-// group_name = group.groupName,
-// group_description = group.groupDescription,
-// list_of_roles = group.listOfRoles,
-// is_enabled = group.isEnabled
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getGroups,
-// implementedInApiVersion,
-// nameOf(getGroups),
-// "GET",
-// "/management/groups",
-// "Get Groups",
-// s"""Get all groups. Optionally filter by bank_id.
-// |
-// |Query parameters:
-// |- bank_id (optional): Filter groups by bank. Use "null" or omit for system-level groups.
-// |
-// |Requires either:
-// |- CanGetGroupsAtAllBanks (for any/all groups)
-// |- CanGetGroupsAtOneBank (for groups at specific bank with bank_id parameter)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// GroupsJsonV600(
-// groups = List(
-// GroupJsonV600(
-// group_id = "group-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// group_description = "Standard teller roles",
-// list_of_roles = List("CanGetCustomer", "CanGetAccount"),
-// is_enabled = true
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup),
-// Some(List(canGetGroupsAtAllBanks, canGetGroupsAtOneBank))
-// )
-//
-// lazy val getGroups: OBPEndpoint = {
-// case "management" :: "groups" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// bankIdParam = httpParams.find(_.name == "bank_id").flatMap(_.values.headOption)
-// bankIdFilter = bankIdParam match {
-// case Some("null") | Some("") => None
-// case Some(id) => Some(id)
-// case None => None
-// }
-// _ <- bankIdFilter match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canGetGroupsAtOneBank :: canGetGroupsAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canGetGroupsAtAllBanks, callContext)
-// }
-// groups <- bankIdFilter match {
-// case Some(bankId) =>
-// code.group.GroupTrait.group.vend.getGroupsByBankId(Some(bankId)) map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get groups", 400)
-// }
-// case None if bankIdParam.isDefined =>
-// code.group.GroupTrait.group.vend.getGroupsByBankId(None) map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get groups", 400)
-// }
-// case None =>
-// code.group.GroupTrait.group.vend.getAllGroups() map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get groups", 400)
-// }
-// }
-// } yield {
-// val response = GroupsJsonV600(
-// groups = groups.map(group =>
-// GroupJsonV600(
-// group_id = group.groupId,
-// bank_id = group.bankId,
-// group_name = group.groupName,
-// group_description = group.groupDescription,
-// list_of_roles = group.listOfRoles,
-// is_enabled = group.isEnabled
-// )
-// )
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateGroup,
-// implementedInApiVersion,
-// nameOf(updateGroup),
-// "PUT",
-// "/management/groups/GROUP_ID",
-// "Update Group",
-// s"""Update a group. All fields are optional.
-// |
-// |Requires either:
-// |- CanUpdateGroupAtAllBanks (for any group)
-// |- CanUpdateGroupAtOneBank (for groups at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// PutGroupJsonV600(
-// group_name = Some("Updated Teller Group"),
-// group_description = Some("Updated description"),
-// list_of_roles = Some(List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction", "CanGetTransaction")),
-// is_enabled = Some(true)
-// ),
-// GroupJsonV600(
-// group_id = "group-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Updated Teller Group",
-// group_description = "Updated description",
-// list_of_roles = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction", "CanGetTransaction"),
-// is_enabled = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagGroup),
-// Some(List(canUpdateGroupAtAllBanks, canUpdateGroupAtOneBank))
-// )
-//
-// lazy val updateGroup: OBPEndpoint = {
-// case "management" :: "groups" :: groupId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutGroupJsonV600", 400, callContext) {
-// json.extract[PutGroupJsonV600]
-// }
-// existingGroup <- Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// _ <- existingGroup.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canUpdateGroupAtOneBank :: canUpdateGroupAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canUpdateGroupAtAllBanks, callContext)
-// }
-// updatedGroup <- Future {
-// code.group.GroupTrait.group.vend.updateGroup(
-// groupId,
-// putJson.group_name,
-// putJson.group_description,
-// putJson.list_of_roles,
-// putJson.is_enabled
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update group", 400)
-// }
-// } yield {
-// val response = GroupJsonV600(
-// group_id = updatedGroup.groupId,
-// bank_id = updatedGroup.bankId,
-// group_name = updatedGroup.groupName,
-// group_description = updatedGroup.groupDescription,
-// list_of_roles = updatedGroup.listOfRoles,
-// is_enabled = updatedGroup.isEnabled
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createUser,
-// implementedInApiVersion,
-// nameOf(createUser),
-// "POST",
-// "/users",
-// "Create User (self-registration)",
-// s"""Creates OBP user.
-// | No authorisation required.
-// |
-// | Mimics current webform to Register.
-// |
-// | Requires username(email), password, first_name, last_name, and email.
-// |
-// | Validation checks performed:
-// | - Password must meet strong password requirements (InvalidStrongPasswordFormat error if not)
-// | - Username must be unique (409 error if username already exists)
-// | - All required fields must be present in valid JSON format
-// |
-// | Email validation behavior:
-// | - Controlled by property 'authUser.skipEmailValidation' (default: false)
-// | - When false: User is created with validated=false and a validation email is sent to the user's email address
-// | - The validation link is constructed using the `portal_external_url` property which must be set (currently: `${APIUtil.getPropsValue("portal_external_url", "not set")}`).
-// | - When true: User is created with validated=true and no validation email is sent
-// | - Default entitlements are granted immediately regardless of validation status
-// |
-// | Note: If email validation is required (skipEmailValidation=false), the user must click the validation link
-// | in the email before they can log in, even though entitlements are already granted.
-// |
-// |""",
-// createUserJsonV600,
-// userJsonV200,
-// List(InvalidJsonFormat, InvalidStrongPasswordFormat, DuplicateUsername, ExternalUserCheckFailed, "Error occurred during user creation.", UnknownError),
-// List(apiTagUser, apiTagOnboarding))
-//
-// lazy val createUser: OBPEndpoint = {
-// case "users" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// // STEP 1: Extract and validate JSON structure
-// postedData <- NewStyle.function.tryons(ErrorMessages.InvalidJsonFormat, 400, cc.callContext) {
-// json.extract[code.api.v6_0_0.CreateUserJsonV600]
-// }
-//
-// // STEP 2: Validate password strength
-// _ <- Helper.booleanToFuture(ErrorMessages.InvalidStrongPasswordFormat, 400, cc.callContext) {
-// fullPasswordValidation(postedData.password)
-// }
-//
-// // STEP 3: Check username uniqueness (returns 409 Conflict if exists)
-// _ <- Helper.booleanToFuture(ErrorMessages.DuplicateUsername, 409, cc.callContext) {
-// code.model.dataAccess.AuthUser.find(net.liftweb.mapper.By(code.model.dataAccess.AuthUser.username, postedData.username)).isEmpty
-// }
-//
-// // STEP 4: Create AuthUser object
-// userCreated <- Future {
-// code.model.dataAccess.AuthUser.create
-// .firstName(postedData.first_name)
-// .lastName(postedData.last_name)
-// .username(postedData.username)
-// .email(postedData.email)
-// .password(postedData.password)
-// .validated(APIUtil.getPropsAsBoolValue("authUser.skipEmailValidation", defaultValue = false))
-// }
-//
-// // STEP 5: Validate Lift field validators
-// _ <- Helper.booleanToFuture(ErrorMessages.InvalidJsonFormat+userCreated.validate.map(_.msg).mkString(";"), 400, cc.callContext) {
-// userCreated.validate.size == 0
-// }
-//
-// // STEP 6: Save user to database
-// savedUser <- NewStyle.function.tryons(ErrorMessages.InvalidJsonFormat, 400, cc.callContext) {
-// userCreated.saveMe()
-// }
-//
-// // STEP 7: Verify save was successful
-// _ <- Helper.booleanToFuture(s"$UnknownError Error occurred during user creation.", 400, cc.callContext) {
-// userCreated.saved_?
-// }
-// } yield {
-// // STEP 8: Send validation email (if required)
-// val skipEmailValidation = APIUtil.getPropsAsBoolValue("authUser.skipEmailValidation", defaultValue = false)
-// if (!skipEmailValidation) {
-// APIUtil.getPropsValue("portal_external_url") match {
-// case Full(portalUrl) =>
-// // Create a JWT token with the uniqueId as subject and configurable expiry
-// val expiryMinutes = APIUtil.getPropsAsIntValue("email_validation_token_expiry_minutes", 1440)
-// val claimsSet = new com.nimbusds.jwt.JWTClaimsSet.Builder()
-// .subject(savedUser.uniqueId.get)
-// .expirationTime(new java.util.Date(System.currentTimeMillis() + expiryMinutes * 60L * 1000L))
-// .issueTime(new java.util.Date())
-// .build()
-// val jwtToken = CertificateUtil.jwtWithHmacProtection(claimsSet)
-//
-// val emailValidationLink = portalUrl + "/user-validation?token=" + java.net.URLEncoder.encode(jwtToken, "UTF-8")
-//
-// val textContent = Some(s"Welcome! Please validate your account by clicking the following link: $emailValidationLink")
-// val htmlContent = Some(s"Welcome! Please validate your account by clicking the following link:
$emailValidationLink
")
-// val subjectContent = "Sign up confirmation"
-//
-// val emailContent = code.api.util.CommonsEmailWrapper.EmailContent(
-// from = code.model.dataAccess.AuthUser.emailFrom,
-// to = List(savedUser.email.get),
-// bcc = code.model.dataAccess.AuthUser.bccEmail.toList,
-// subject = subjectContent,
-// textContent = textContent,
-// htmlContent = htmlContent
-// )
-//
-// code.api.util.CommonsEmailWrapper.sendHtmlEmail(emailContent)
-// case _ =>
-// logger.error("portal_external_url is not set in props. Cannot send validation email.")
-// }
-// }
-//
-// // STEP 9: Grant default entitlements
-// code.model.dataAccess.AuthUser.grantDefaultEntitlementsToAuthUser(savedUser)
-//
-// // STEP 10: Return JSON response
-// val json = JSONFactory200.createUserJSONfromAuthUser(userCreated)
-// (json, HttpCode.`201`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteEntitlement,
-// implementedInApiVersion,
-// nameOf(deleteEntitlement),
-// "DELETE",
-// "/entitlements/ENTITLEMENT_ID",
-// "Delete Entitlement",
-// s"""Delete Entitlement specified by ENTITLEMENT_ID
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Requires the $canDeleteEntitlementAtAnyBank role.
-// |
-// |This endpoint is idempotent - if the entitlement does not exist, it returns 204 No Content.
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// EntitlementCannotBeDeleted,
-// UnknownError
-// ),
-// List(apiTagRole, apiTagUser, apiTagEntitlement),
-// Some(List(canDeleteEntitlementAtAnyBank)))
-//
-// lazy val deleteEntitlement: OBPEndpoint = {
-// case "entitlements" :: entitlementId :: Nil JsonDelete _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// // TODO: This role check may be redundant since role is already specified in ResourceDoc.
-// // See ideas/should_fix_role_docs.md for details on removing duplicate role checks.
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteEntitlementAtAnyBank, callContext)
-// entitlementBox <- Future(Entitlement.entitlement.vend.getEntitlementById(entitlementId))
-// _ <- entitlementBox match {
-// case Full(entitlement) =>
-// // Entitlement exists - delete it
-// Future(Entitlement.entitlement.vend.deleteEntitlement(Some(entitlement))) map {
-// case Full(true) => Full(())
-// case _ => ObpApiFailure(EntitlementCannotBeDeleted, 500, callContext)
-// }
-// case _ =>
-// // Entitlement not found - idempotent delete returns success
-// Future.successful(Full(()))
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getRolesWithEntitlementCountsAtAllBanks,
-// implementedInApiVersion,
-// nameOf(getRolesWithEntitlementCountsAtAllBanks),
-// "GET",
-// "/management/roles-with-entitlement-counts",
-// "Get Roles with Entitlement Counts",
-// s"""Returns all available roles with the count of entitlements that use each role.
-// |
-// |This endpoint provides statistics about role usage across all banks by counting
-// |how many entitlements have been granted for each role.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |Requires the CanGetRolesWithEntitlementCountsAtAllBanks role.
-// |
-// |""",
-// EmptyBody,
-// RolesWithEntitlementCountsJsonV600(
-// roles = List(
-// RoleWithEntitlementCountJsonV600(
-// role = "CanGetCustomer",
-// requires_bank_id = true,
-// entitlement_count = 5
-// ),
-// RoleWithEntitlementCountJsonV600(
-// role = "CanGetBank",
-// requires_bank_id = false,
-// entitlement_count = 3
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagRole, apiTagEntitlement),
-// Some(List(canGetRolesWithEntitlementCountsAtAllBanks))
-// )
-//
-// lazy val getRolesWithEntitlementCountsAtAllBanks: OBPEndpoint = {
-// case "management" :: "roles-with-entitlement-counts" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetRolesWithEntitlementCountsAtAllBanks, callContext)
-//
-// // Get all available roles
-// allRoles = ApiRole.availableRoles.sorted
-//
-// // Get entitlement counts for each role
-// rolesWithCounts <- Future.sequence {
-// allRoles.map { role =>
-// Entitlement.entitlement.vend.getEntitlementsByRoleFuture(role).map { entitlementsBox =>
-// val count = entitlementsBox.map(_.length).getOrElse(0)
-// (role, count)
-// }
-// }
-// }
-// } yield {
-// val json = JSONFactory600.createRolesWithEntitlementCountsJson(rolesWithCounts)
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteGroup,
-// implementedInApiVersion,
-// nameOf(deleteGroup),
-// "DELETE",
-// "/management/groups/GROUP_ID",
-// "Delete Group",
-// s"""Delete a Group.
-// |
-// |Requires either:
-// |- CanDeleteGroupAtAllBanks (for any group)
-// |- CanDeleteGroupAtOneBank (for groups at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup),
-// Some(List(canDeleteGroupAtAllBanks, canDeleteGroupAtOneBank))
-// )
-//
-// lazy val deleteGroup: OBPEndpoint = {
-// case "management" :: "groups" :: groupId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// existingGroup <- Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// _ <- existingGroup.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canDeleteGroupAtOneBank :: canDeleteGroupAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canDeleteGroupAtAllBanks, callContext)
-// }
-// deleted <- Future {
-// code.group.GroupTrait.group.vend.deleteGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot delete group", 400)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// addUserToGroup,
-// implementedInApiVersion,
-// nameOf(addUserToGroup),
-// "POST",
-// "/users/USER_ID/group-entitlements",
-// "Grant User Membership to Group Entitlements",
-// s"""Grant the User Group Entitlements.
-// |
-// |This endpoint creates entitlements for every Role in the Group. If the user
-// |already has a particular role at the same bank, that entitlement is skipped (not duplicated).
-// |
-// |Each entitlement created will have:
-// |- group_id set to the group ID
-// |- process set to "GROUP_MEMBERSHIP"
-// |
-// |**Response Fields:**
-// |- target_entitlements: All roles defined in the group (the complete list of entitlements that this group aims to grant)
-// |- entitlements_created: Roles that were newly created as entitlements during this operation
-// |- entitlements_skipped: Roles that the user already possessed, so no new entitlement was created
-// |
-// |Note: target_entitlements = entitlements_created + entitlements_skipped
-// |
-// |Requires either:
-// |- CanAddUserToGroupAtAllBanks (for any group)
-// |- CanAddUserToGroupAtOneBank (for groups at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// PostGroupMembershipJsonV600(
-// group_id = "group-id-123"
-// ),
-// AddUserToGroupResponseJsonV600(
-// group_id = "group-id-123",
-// user_id = "user-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// target_entitlements = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction"),
-// entitlements_created = List("CanGetCustomer", "CanGetAccount"),
-// entitlements_skipped = List("CanCreateTransaction")
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagGroup, apiTagUser, apiTagEntitlement),
-// Some(List(canAddUserToGroupAtAllBanks, canAddUserToGroupAtOneBank))
-// )
-//
-// lazy val addUserToGroup: OBPEndpoint = {
-// case "users" :: userId :: "group-entitlements" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostGroupMembershipJsonV600", 400, callContext) {
-// json.extract[PostGroupMembershipJsonV600]
-// }
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// group <- Future {
-// code.group.GroupTrait.group.vend.getGroup(postJson.group_id)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// _ <- group.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canAddUserToGroupAtOneBank :: canAddUserToGroupAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canAddUserToGroupAtAllBanks, callContext)
-// }
-// _ <- Helper.booleanToFuture(failMsg = s"$UnknownError Group is not enabled", 400, callContext) {
-// group.isEnabled
-// }
-// // Get existing entitlements for this user
-// existingEntitlements <- Future {
-// Entitlement.entitlement.vend.getEntitlementsByUserId(userId)
-// }
-// // Create entitlements for all roles in the group, tracking which were added vs already present
-// entitlementResults <- Future.sequence {
-// group.listOfRoles.map { roleName =>
-// Future {
-// // Check if user already has this role at this bank
-// val alreadyHasRole = existingEntitlements.toOption.exists(_.exists { ent =>
-// ent.roleName == roleName && ent.bankId == group.bankId.getOrElse("")
-// })
-//
-// if (!alreadyHasRole) {
-// Entitlement.entitlement.vend.addEntitlement(
-// group.bankId.getOrElse(""),
-// userId,
-// roleName,
-// "manual",
-// None,
-// Some(postJson.group_id),
-// Some("GROUP_MEMBERSHIP")
-// )
-// (roleName, true) // true means it was added
-// } else {
-// (roleName, false) // false means it was already present
-// }
-// }
-// }
-// }
-// entitlementsAdded = entitlementResults.filter(_._2).map(_._1)
-// entitlementsAlreadyPresent = entitlementResults.filterNot(_._2).map(_._1)
-// } yield {
-// val response = AddUserToGroupResponseJsonV600(
-// group_id = group.groupId,
-// user_id = userId,
-// bank_id = group.bankId,
-// group_name = group.groupName,
-// target_entitlements = group.listOfRoles,
-// entitlements_created = entitlementsAdded,
-// entitlements_skipped = entitlementsAlreadyPresent
-// )
-// (response, HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserGroupMemberships,
-// implementedInApiVersion,
-// nameOf(getUserGroupMemberships),
-// "GET",
-// "/users/USER_ID/group-entitlements",
-// "Get User's Group Memberships",
-// s"""Get all groups a user is a member of.
-// |
-// |Returns groups where the user has entitlements with process = "GROUP_MEMBERSHIP".
-// |
-// |The response includes:
-// |- list_of_entitlements: entitlements the user currently has from this group membership
-// |
-// |Requires either:
-// |- CanGetUserGroupMembershipsAtAllBanks (for any user)
-// |- CanGetUserGroupMembershipsAtOneBank (for users at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// UserGroupMembershipsJsonV600(
-// group_entitlements = List(
-// UserGroupMembershipJsonV600(
-// group_id = "group-id-123",
-// user_id = "user-id-123",
-// bank_id = Some("gh.29.uk"),
-// group_name = "Teller Group",
-// list_of_entitlements = List("CanGetCustomer", "CanGetAccount", "CanCreateTransaction")
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup, apiTagUser, apiTagEntitlement),
-// Some(List(canGetUserGroupMembershipsAtAllBanks, canGetUserGroupMembershipsAtOneBank))
-// )
-//
-// lazy val getUserGroupMemberships: OBPEndpoint = {
-// case "users" :: userId :: "group-entitlements" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// // Get all entitlements for this user that came from groups
-// entitlements <- Future {
-// Entitlement.entitlement.vend.getEntitlementsByUserId(userId)
-// }
-// groupEntitlements = entitlements.toOption.getOrElse(List.empty).filter(_.process == Some("GROUP_MEMBERSHIP"))
-// // Get unique group IDs
-// groupIds = groupEntitlements.flatMap(_.groupId).distinct
-// // Check permissions for each bank
-// _ <- Future.sequence {
-// groupIds.flatMap { groupId =>
-// // Get the group to find its bank_id
-// code.group.GroupTrait.group.vend.getGroup(groupId).toOption.map { group =>
-// group.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canGetUserGroupMembershipsAtOneBank :: canGetUserGroupMembershipsAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canGetUserGroupMembershipsAtAllBanks, callContext)
-// }
-// }
-// }
-// }
-// // Get full group details
-// groups <- Future.sequence {
-// groupIds.map { groupId =>
-// Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// }
-// }
-// }
-// validGroups = groups.flatten
-// } yield {
-// val memberships = validGroups.map { group =>
-// // Get entitlements for this user that came from this specific group
-// val groupSpecificEntitlements = groupEntitlements
-// .filter(_.groupId.contains(group.groupId))
-// .map(_.roleName)
-// .distinct
-//
-// UserGroupMembershipJsonV600(
-// group_id = group.groupId,
-// user_id = userId,
-// bank_id = group.bankId,
-// group_name = group.groupName,
-// list_of_entitlements = groupSpecificEntitlements
-// )
-// }
-// (UserGroupMembershipsJsonV600(group_entitlements = memberships), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getGroupEntitlements,
-// implementedInApiVersion,
-// nameOf(getGroupEntitlements),
-// "GET",
-// "/management/groups/GROUP_ID/entitlements",
-// "Get Group Entitlements",
-// s"""Get all entitlements that have been granted from a specific group.
-// |
-// |This returns all entitlements where the group_id matches the specified GROUP_ID.
-// |
-// |Requires:
-// |- CanGetEntitlementsForAnyBank
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// GroupEntitlementsJsonV600(
-// entitlements = List(
-// GroupEntitlementJsonV600(
-// entitlement_id = "entitlement-id-123",
-// role_name = "CanGetCustomer",
-// bank_id = "gh.29.uk",
-// user_id = "user-id-123",
-// username = "susan.uk.29@example.com",
-// group_id = Some("group-id-123"),
-// process = Some("GROUP_MEMBERSHIP")
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup, apiTagEntitlement),
-// Some(List(canGetEntitlementsForAnyBank))
-// )
-//
-// lazy val getGroupEntitlements: OBPEndpoint = {
-// case "management" :: "groups" :: groupId :: "entitlements" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// // Verify the group exists
-// group <- Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// // Get entitlements by group_id
-// groupEntitlements <- Entitlement.entitlement.vend.getEntitlementsByGroupId(groupId) map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get entitlements", 400)
-// }
-// // Get usernames for each entitlement
-// entitlementsWithUsernames <- Future.sequence {
-// groupEntitlements.map { ent =>
-// Users.users.vend.getUserByUserIdFuture(ent.userId).map { userBox =>
-// val username = userBox.map(_.name).getOrElse("")
-// GroupEntitlementJsonV600(
-// entitlement_id = ent.entitlementId,
-// role_name = ent.roleName,
-// bank_id = ent.bankId,
-// user_id = ent.userId,
-// username = username,
-// group_id = ent.groupId,
-// process = ent.process
-// )
-// }
-// }
-// }
-// } yield {
-// val entitlementCount = entitlementsWithUsernames.length
-// logger.info(s"getGroupEntitlements called for group_id: $groupId, returned $entitlementCount records")
-// (GroupEntitlementsJsonV600(entitlements = entitlementsWithUsernames), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// removeUserFromGroup,
-// implementedInApiVersion,
-// nameOf(removeUserFromGroup),
-// "DELETE",
-// "/users/USER_ID/group-entitlements/GROUP_ID",
-// "Remove User from Group",
-// s"""Remove a user from a group. This will delete all entitlements that were created by this group membership.
-// |
-// |Only removes entitlements with:
-// |- group_id matching GROUP_ID
-// |- process = "GROUP_MEMBERSHIP"
-// |
-// |Requires either:
-// |- CanRemoveUserFromGroupAtAllBanks (for any group)
-// |- CanRemoveUserFromGroupAtOneBank (for groups at specific bank)
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagGroup, apiTagUser, apiTagEntitlement),
-// Some(List(canRemoveUserFromGroupAtAllBanks, canRemoveUserFromGroupAtOneBank))
-// )
-//
-// lazy val removeUserFromGroup: OBPEndpoint = {
-// case "users" :: userId :: "group-entitlements" :: groupId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
-// group <- Future {
-// code.group.GroupTrait.group.vend.getGroup(groupId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Group not found", 404)
-// }
-// _ <- group.bankId match {
-// case Some(bankId) =>
-// NewStyle.function.hasAtLeastOneEntitlement(bankId, u.userId, canRemoveUserFromGroupAtOneBank :: canRemoveUserFromGroupAtAllBanks :: Nil, callContext)
-// case None =>
-// NewStyle.function.hasEntitlement("", u.userId, canRemoveUserFromGroupAtAllBanks, callContext)
-// }
-// // Get all entitlements for this user from this group
-// entitlements <- Future {
-// Entitlement.entitlement.vend.getEntitlementsByUserId(userId)
-// }
-// groupEntitlements = entitlements.toOption.getOrElse(List.empty).filter(e =>
-// e.groupId == Some(groupId) && e.process == Some("GROUP_MEMBERSHIP")
-// )
-// // Delete all entitlements from this group
-// _ <- Future.sequence {
-// groupEntitlements.map { entitlement =>
-// Future {
-// Entitlement.entitlement.vend.deleteEntitlement(Full(entitlement))
-// }
-// }
-// }
-// } yield {
-// (Full(true), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemViews,
-// implementedInApiVersion,
-// nameOf(getSystemViews),
-// "GET",
-// "/management/system-views",
-// "Get System Views",
-// s"""Get all system views.
-// |
-// |System views are predefined views that apply to all accounts, such as:
-// |- owner
-// |- accountant
-// |- auditor
-// |- standard
-// |
-// |Each view is returned with an `allowed_actions` array containing all permissions for that view.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ViewsJsonV600(List(
-// ViewJsonV600(
-// bank_id = "",
-// account_id = "",
-// view_id = "owner",
-// view_name = "Owner",
-// description = "The owner of the account",
-// metadata_view = "owner",
-// is_public = false,
-// is_system = true,
-// is_firehose = Some(false),
-// alias = "private",
-// hide_metadata_if_alias_used = false,
-// can_grant_access_to_views = List("owner"),
-// can_revoke_access_to_views = List("owner"),
-// allowed_actions = List("can_see_transaction_amount", "can_see_bank_account_balance")
-// )
-// )),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemView, apiTagView),
-// Some(List(canGetSystemViews))
-// )
-//
-// lazy val getSystemViews: OBPEndpoint = {
-// case "management" :: "system-views" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// views <- Views.views.vend.getSystemViews()
-// } yield {
-// (JSONFactory600.createViewsJsonV600(views), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemViewById,
-// implementedInApiVersion,
-// nameOf(getSystemViewById),
-// "GET",
-// "/management/system-views/VIEW_ID",
-// "Get System View",
-// s"""Get a single system view by its ID.
-// |
-// |System views are predefined views that apply to all accounts, such as:
-// |- owner
-// |- accountant
-// |- auditor
-// |- standard
-// |
-// |The view is returned with an `allowed_actions` array containing all permissions for that view.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ViewJsonV600(
-// bank_id = "",
-// account_id = "",
-// view_id = "owner",
-// view_name = "Owner",
-// description = "The owner of the account. Has full privileges.",
-// metadata_view = "owner",
-// is_public = false,
-// is_system = true,
-// is_firehose = Some(false),
-// alias = "private",
-// hide_metadata_if_alias_used = false,
-// can_grant_access_to_views = List("owner", "accountant"),
-// can_revoke_access_to_views = List("owner", "accountant"),
-// allowed_actions = List(
-// "can_see_transaction_amount",
-// "can_see_bank_account_balance",
-// "can_add_comment",
-// "can_create_custom_view"
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// SystemViewNotFound,
-// UnknownError
-// ),
-// List(apiTagSystemView, apiTagView),
-// Some(List(canGetSystemViews))
-// )
-//
-// lazy val getSystemViewById: OBPEndpoint = {
-// case "management" :: "system-views" :: viewId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// view <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-// } yield {
-// (JSONFactory600.createViewJsonV600(view), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-//// staticResourceDocs += ResourceDoc(
-//// getSystemView,
-//// implementedInApiVersion,
-//// nameOf(getSystemView),
-//// "GET",
-//// "/system-views/VIEW_ID",
-//// "Get System View",
-//// s"""Get a single system view by its ID.
-//// |
-//// |System views are predefined views that apply to all accounts, such as:
-//// |- owner
-//// |- accountant
-//// |- auditor
-//// |- standard
-//// |
-//// |This endpoint returns the view with an `allowed_actions` array containing all permissions.
-//// |
-//// |${userAuthenticationMessage(true)}
-//// |
-//// |""".stripMargin,
-//// EmptyBody,
-//// ViewJsonV600(
-//// view_id = "owner",
-//// view_name = "Owner",
-//// description = "The owner of the account. Has full privileges.",
-//// metadata_view = "owner",
-//// is_public = false,
-//// is_system = true,
-//// is_firehose = Some(false),
-//// alias = "private",
-//// hide_metadata_if_alias_used = false,
-//// can_grant_access_to_views = List("owner", "accountant"),
-//// can_revoke_access_to_views = List("owner", "accountant"),
-//// allowed_actions = List(
-//// "can_see_transaction_amount",
-//// "can_see_bank_account_balance",
-//// "can_add_comment",
-//// "can_create_custom_view"
-//// )
-//// ),
-//// List(
-//// AuthenticatedUserIsRequired,
-//// UserHasMissingRoles,
-//// SystemViewNotFound,
-//// UnknownError
-//// ),
-//// List(apiTagSystemView, apiTagView),
-//// Some(List(canGetSystemViews))
-//// )
-////
-//// lazy val getSystemView: OBPEndpoint = {
-//// case "system-views" :: viewId :: Nil JsonGet _ => {
-//// cc => implicit val ec = EndpointContext(Some(cc))
-//// for {
-//// (Full(u), callContext) <- authenticatedAccess(cc)
-//// view <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-//// } yield {
-//// (JSONFactory600.createViewJsonV600(view), HttpCode.`200`(callContext))
-//// }
-//// }
-//// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateSystemView,
-// implementedInApiVersion,
-// nameOf(updateSystemView),
-// "PUT",
-// "/system-views/VIEW_ID",
-// "Update System View",
-// s"""Update an existing system view.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |The JSON sent is the same as during view creation, with one difference: the 'name' field
-// |of a view is not editable (it is only set when a view is created).
-// |
-// |The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.
-// |
-// |The response contains the updated view with an `allowed_actions` array.
-// |
-// |""".stripMargin,
-// UpdateViewJsonV600(
-// description = "This is the owner view",
-// metadata_view = "owner",
-// is_public = false,
-// is_firehose = Some(false),
-// which_alias_to_use = "private",
-// hide_metadata_if_alias_used = false,
-// allowed_actions = List(
-// "can_see_transaction_amount",
-// "can_see_bank_account_balance",
-// "can_add_comment"
-// ),
-// can_grant_access_to_views = Some(List("owner", "accountant")),
-// can_revoke_access_to_views = Some(List("owner", "accountant"))
-// ),
-// ViewJsonV600(
-// bank_id = "",
-// account_id = "",
-// view_id = "owner",
-// view_name = "Owner",
-// description = "This is the owner view",
-// metadata_view = "owner",
-// is_public = false,
-// is_system = true,
-// is_firehose = Some(false),
-// alias = "private",
-// hide_metadata_if_alias_used = false,
-// can_grant_access_to_views = List("owner", "accountant"),
-// can_revoke_access_to_views = List("owner", "accountant"),
-// allowed_actions = List(
-// "can_see_transaction_amount",
-// "can_see_bank_account_balance",
-// "can_add_comment"
-// )
-// ),
-// List(
-// InvalidJsonFormat,
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// SystemViewNotFound,
-// SystemViewCannotBePublicError,
-// UnknownError
-// ),
-// List(apiTagSystemView, apiTagView),
-// Some(List(canUpdateSystemView))
-// )
-//
-// lazy val updateSystemView: OBPEndpoint = {
-// case "system-views" :: viewId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUpdateSystemView, callContext)
-// updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the UpdateViewJsonV600", 400, callContext) {
-// json.extract[UpdateViewJsonV600]
-// }
-// _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode = 400, cc = callContext) {
-// updateJson.is_public == false
-// }
-// _ <- ViewNewStyle.systemView(ViewId(viewId), callContext)
-// updatedView <- ViewNewStyle.updateSystemView(ViewId(viewId), updateJson.toUpdateViewJson, callContext)
-// } yield {
-// (JSONFactory600.createViewJsonV600(updatedView), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getViewPermissions,
-// implementedInApiVersion,
-// nameOf(getViewPermissions),
-// "GET",
-// "/management/view-permissions",
-// "Get View Permissions",
-// s"""Get a list of all available view permissions.
-// |
-// |This endpoint returns all the available permissions that can be assigned to views,
-// |organized by category. These permissions control what actions and data can be accessed
-// |through a view.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |The response contains all available view permission names that can be used in the
-// |`allowed_actions` field when creating or updating custom views.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ViewPermissionsJsonV600(
-// permissions = List(
-// ViewPermissionJsonV600("can_see_transaction_amount", "Transaction"),
-// ViewPermissionJsonV600("can_see_bank_account_balance", "Account"),
-// ViewPermissionJsonV600("can_create_custom_view", "View")
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagSystemView, apiTagView),
-// Some(List(canGetViewPermissionsAtAllBanks))
-// )
-//
-// lazy val getViewPermissions: OBPEndpoint = {
-// case "management" :: "view-permissions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetViewPermissionsAtAllBanks, callContext)
-// } yield {
-// import Constant._
-//
-// // Helper function to determine category from permission name
-// def categorizePermission(permission: String): String = {
-// permission match {
-// case p if p.contains("transaction") && !p.contains("request") => "Transaction"
-// case p if p.contains("bank_account") || p.contains("bank_routing") || p.contains("available_funds") => "Account"
-// case p if p.contains("other_account") || p.contains("other_bank") ||
-// p.contains("counterparty") || p.contains("more_info") ||
-// p.contains("url") || p.contains("corporates") ||
-// p.contains("location") || p.contains("alias") => "Counterparty"
-// case p if p.contains("comment") || p.contains("tag") ||
-// p.contains("image") || p.contains("where_tag") => "Metadata"
-// case p if p.contains("transaction_request") || p.contains("direct_debit") ||
-// p.contains("standing_order") => "Transaction Request"
-// case p if p.contains("view") => "View"
-// case p if p.contains("grant") || p.contains("revoke") => "Access Control"
-// case _ => "Other"
-// }
-// }
-//
-// // Return all view permissions directly from the constants with generated categories
-// val permissions = ALL_VIEW_PERMISSION_NAMES.map { permission =>
-// ViewPermissionJsonV600(permission, categorizePermission(permission))
-// }.sortBy(p => (p.category, p.permission))
-//
-// (ViewPermissionsJsonV600(permissions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomViewManagement,
-// implementedInApiVersion,
-// nameOf(createCustomViewManagement),
-// "POST",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/views",
-// "Create Custom View (Management)",
-// s"""Create a custom view on a bank account via management endpoint.
-// |
-// |This is a **management endpoint** that requires the `CanCreateCustomView` role (entitlement).
-// |
-// |This endpoint provides a simpler, role-based authorization model compared to the original
-// |v3.0.0 endpoint which requires view-level permissions. Use this endpoint when you want to
-// |grant view creation ability through direct role assignment rather than through view access.
-// |
-// |For the original endpoint that checks account-level view permissions, see:
-// |POST /obp/v3.0.0/banks/BANK_ID/accounts/ACCOUNT_ID/views
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |The 'alias' field in the JSON can take one of three values:
-// |
-// | * _public_: to use the public alias if there is one specified for the other account.
-// | * _private_: to use the private alias if there is one specified for the other account.
-// |
-// | * _''(empty string)_: to use no alias; the view shows the real name of the other account.
-// |
-// | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.
-// |
-// | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.
-// |
-// | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.
-// |
-// | You MUST use a leading _ (underscore) in the view name because other view names are reserved for OBP [system views](/index#group-View-System).
-// |
-// |""".stripMargin,
-// createViewJsonV300,
-// viewJsonV300,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// InvalidCustomViewFormat,
-// BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount),
-// Some(List(canCreateCustomView))
-// )
-//
-// lazy val createCustomViewManagement: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// createViewJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CreateViewJson ", 400, callContext) {
-// json.extract[CreateViewJson]
-// }
-// //customer views are started with `_`, eg _life, _work, and System views start with letter, eg: owner
-// _ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat + s"Current view_name (${createViewJson.name})", cc = callContext) {
-// isValidCustomViewName(createViewJson.name)
-// }
-// (account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// (view, callContext) <- ViewNewStyle.createCustomView(BankIdAccountId(bankId, accountId), createViewJson, callContext)
-// } yield {
-// (JSONFactory600.createViewJsonV600(view), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomViews,
-// implementedInApiVersion,
-// nameOf(getCustomViews),
-// "GET",
-// "/management/custom-views",
-// "Get Custom Views",
-// s"""Get all custom views.
-// |
-// |Custom views are user-created views with names starting with underscore (_), such as:
-// |- _work
-// |- _personal
-// |- _audit
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ViewsJsonV600(List()),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagView, apiTagSystemView),
-// Some(List(canGetCustomViews))
-// )
-//
-// lazy val getCustomViews: OBPEndpoint = {
-// case "management" :: "custom-views" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// customViews <- Future { ViewDefinition.getCustomViews() }
-// } yield {
-// (JSONFactory600.createViewsJsonV600(customViews), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomViewById,
-// implementedInApiVersion,
-// nameOf(getCustomViewById),
-// "GET",
-// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID",
-// "Get Custom View",
-// s"""Get a single custom view by bank, account, and view ID.
-// |
-// |Custom views are user-created views with names starting with underscore (_), such as:
-// |- _work
-// |- _personal
-// |- _audit
-// |
-// |Custom views are unique per bank_id, account_id, and view_id combination.
-// |
-// |The view is returned with an `allowed_actions` array containing all permissions for that view.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ViewJsonV600(
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = "_work",
-// view_name = "Work",
-// description = "A custom view for work-related transactions.",
-// metadata_view = "_work",
-// is_public = false,
-// is_system = false,
-// is_firehose = Some(false),
-// alias = "private",
-// hide_metadata_if_alias_used = false,
-// can_grant_access_to_views = List("_work"),
-// can_revoke_access_to_views = List("_work"),
-// allowed_actions = List(
-// "can_see_transaction_amount",
-// "can_see_bank_account_balance",
-// "can_add_comment"
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ViewNotFound,
-// UnknownError
-// ),
-// List(apiTagView, apiTagSystemView),
-// Some(List(canGetCustomViews))
-// )
-//
-// lazy val getCustomViewById: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: viewId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// view <- ViewNewStyle.customView(ViewId(viewId), BankIdAccountId(bankId, accountId), callContext)
-// } yield {
-// (JSONFactory600.createViewJsonV600(view), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// resetPasswordUrl,
-// implementedInApiVersion,
-// nameOf(resetPasswordUrl),
-// "POST",
-// "/management/user/reset-password-url",
-// "Create Password Reset URL and Send Email",
-// s"""Create a password reset URL for a user and automatically send it via email.
-// |
-// |Authentication is Required.
-// |
-// |Behavior:
-// |- Generates a unique password reset token
-// |- Creates a reset URL using the portal_external_url property (falls back to API hostname)
-// |- Sends an email to the user with the reset link
-// |- Returns the reset URL in the response for logging/tracking purposes
-// |
-// |Required fields:
-// |- username: The user's username (typically email)
-// |- email: The user's email address (must match username)
-// |- user_id: The user's UUID
-// |
-// |The user must exist and be validated before a reset URL can be generated.
-// |
-// |Email configuration must be set up correctly for email delivery to work.
-// |
-// |""".stripMargin,
-// PostResetPasswordUrlJsonV600(
-// "user@example.com",
-// "user@example.com",
-// "74a8ebcc-10e4-4036-bef3-9835922246bf"
-// ),
-// ResetPasswordUrlJsonV600(
-// "https://api.example.com/reset-password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canCreateResetPasswordUrl))
-// )
-//
-// lazy val resetPasswordUrl: OBPEndpoint = {
-// case "management" :: "user" :: "reset-password-url" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordUrlJsonV600]}",
-// 400,
-// callContext
-// ) {
-// json.extract[PostResetPasswordUrlJsonV600]
-// }
-// // Find the AuthUser
-// authUserBox <- Future {
-// code.model.dataAccess.AuthUser.find(
-// net.liftweb.mapper.By(code.model.dataAccess.AuthUser.username, postedData.username)
-// )
-// }
-// authUser <- NewStyle.function.tryons(
-// s"$UnknownError User not found or validation failed",
-// 400,
-// callContext
-// ) {
-// authUserBox match {
-// case Full(user) if user.validated.get && user.email.get == postedData.email =>
-// // Verify user_id matches
-// Users.users.vend.getUserByUserId(postedData.user_id) match {
-// case Full(resourceUser) if resourceUser.name == postedData.username &&
-// resourceUser.emailAddress == postedData.email =>
-// user
-// case _ => throw new Exception("User ID does not match username and email")
-// }
-// case _ => throw new Exception("User not found, not validated, or email mismatch")
-// }
-// }
-// portalUrl <- APIUtil.getPropsValue("portal_external_url") match {
-// case Full(url) => Future.successful(url)
-// case _ => Future.failed(new Exception(s"$IncompleteServerConfiguration portal_external_url is not set in props. It is required to construct the password reset link."))
-// }
-// } yield {
-// // Explicitly type the user to ensure proper method resolution
-// val user: code.model.dataAccess.AuthUser = authUser
-//
-// // Generate new reset token
-// user.uniqueId.set(java.util.UUID.randomUUID().toString.replace("-", ""))
-// user.save
-//
-// // Create a JWT token with the uniqueId as subject and configurable expiry
-// val expiryMinutes = APIUtil.getPropsAsIntValue("password_reset_token_expiry_minutes", 120)
-// val claimsSet = new com.nimbusds.jwt.JWTClaimsSet.Builder()
-// .subject(user.uniqueId.get)
-// .expirationTime(new java.util.Date(System.currentTimeMillis() + expiryMinutes * 60L * 1000L))
-// .issueTime(new java.util.Date())
-// .build()
-// val jwtToken = CertificateUtil.jwtWithHmacProtection(claimsSet)
-//
-// // Construct reset URL using portal_external_url
-// val resetPasswordLink = portalUrl +
-// "/reset-password/" +
-// java.net.URLEncoder.encode(jwtToken, "UTF-8")
-//
-// // Send email using CommonsEmailWrapper (like createUser does)
-// val textContent = Some(s"Please use the following link to reset your password: $resetPasswordLink")
-// val htmlContent = Some(s"Please use the following link to reset your password:
$resetPasswordLink
")
-// val subjectContent = "Reset your password - " + user.username.get
-//
-// val emailContent = code.api.util.CommonsEmailWrapper.EmailContent(
-// from = code.model.dataAccess.AuthUser.emailFrom,
-// to = List(user.email.get),
-// bcc = code.model.dataAccess.AuthUser.bccEmail.toList,
-// subject = subjectContent,
-// textContent = textContent,
-// htmlContent = htmlContent
-// )
-//
-// code.api.util.CommonsEmailWrapper.sendHtmlEmail(emailContent)
-//
-// (
-// ResetPasswordUrlJsonV600(resetPasswordLink),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// resetPasswordUrlAnonymous,
-// implementedInApiVersion,
-// nameOf(resetPasswordUrlAnonymous),
-// "POST",
-// "/users/password-reset-url",
-// "Request Password Reset Email",
-// s"""Request a password reset email for a user. No authentication is required.
-// |
-// |Authentication is NOT Required.
-// |
-// |This endpoint is designed for users who have forgotten their password and cannot log in.
-// |
-// |Behavior:
-// |- Looks up the user by username and email
-// |- Generates a unique password reset token
-// |- Creates a reset URL using the portal_external_url property (falls back to API hostname)
-// |- Sends an email to the user with the reset link
-// |
-// |Required fields:
-// |- username: The user's username (typically email)
-// |- email: The user's email address (must match username)
-// |
-// |The user must exist and be validated before a reset email can be sent.
-// |
-// |Email configuration must be set up correctly for email delivery to work.
-// |
-// |Note: For security reasons, this endpoint returns a generic success message regardless of
-// |whether the user was found, to prevent user enumeration.
-// |
-// |""".stripMargin,
-// PostResetPasswordUrlAnonymousJsonV600(
-// "user@example.com",
-// "user@example.com"
-// ),
-// ResetPasswordUrlAnonymousResponseJsonV600(
-// "If the account exists, a password reset email has been sent."
-// ),
-// List(
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List())
-// )
-//
-// lazy val resetPasswordUrlAnonymous: OBPEndpoint = {
-// case "users" :: "password-reset-url" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordUrlAnonymousJsonV600]}",
-// 400,
-// callContext
-// ) {
-// json.extract[PostResetPasswordUrlAnonymousJsonV600]
-// }
-// } yield {
-// // Look up the user - but always return the same response to prevent user enumeration
-// val authUserBox = code.model.dataAccess.AuthUser.find(
-// net.liftweb.mapper.By(code.model.dataAccess.AuthUser.username, postedData.username)
-// )
-//
-// (authUserBox, APIUtil.getPropsValue("portal_external_url")) match {
-// case (Full(user), Full(portalUrl)) if user.validated.get && user.email.get == postedData.email =>
-// // Generate new reset token
-// user.uniqueId.set(java.util.UUID.randomUUID().toString.replace("-", ""))
-// user.save
-//
-// // Create a JWT token with the uniqueId as subject and configurable expiry
-// val expiryMinutes = APIUtil.getPropsAsIntValue("password_reset_token_expiry_minutes", 120)
-// val claimsSet = new com.nimbusds.jwt.JWTClaimsSet.Builder()
-// .subject(user.uniqueId.get)
-// .expirationTime(new java.util.Date(System.currentTimeMillis() + expiryMinutes * 60L * 1000L))
-// .issueTime(new java.util.Date())
-// .build()
-// val jwtToken = CertificateUtil.jwtWithHmacProtection(claimsSet)
-//
-// // Construct reset URL
-// val resetPasswordLink = portalUrl +
-// "/reset-password/" +
-// java.net.URLEncoder.encode(jwtToken, "UTF-8")
-//
-// // Send email
-// val textContent = Some(s"Please use the following link to reset your password: $resetPasswordLink")
-// val htmlContent = Some(s"Please use the following link to reset your password:
$resetPasswordLink
")
-// val subjectContent = "Reset your password - " + user.username.get
-//
-// val emailContent = code.api.util.CommonsEmailWrapper.EmailContent(
-// from = code.model.dataAccess.AuthUser.emailFrom,
-// to = List(user.email.get),
-// bcc = code.model.dataAccess.AuthUser.bccEmail.toList,
-// subject = subjectContent,
-// textContent = textContent,
-// htmlContent = htmlContent
-// )
-//
-// code.api.util.CommonsEmailWrapper.sendHtmlEmail(emailContent)
-//
-// case (_, Empty) =>
-// logger.error("portal_external_url is not set in props. Cannot send password reset email.")
-//
-// case _ =>
-// // Do nothing - return same response to prevent user enumeration
-// }
-//
-// (
-// ResetPasswordUrlAnonymousResponseJsonV600("If the account exists, a password reset email has been sent."),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// resetPasswordComplete,
-// implementedInApiVersion,
-// nameOf(resetPasswordComplete),
-// "POST",
-// "/users/password",
-// "Complete Password Reset",
-// s"""Complete a password reset using the token received via email.
-// |
-// |Authentication is NOT Required.
-// |
-// |After requesting a password reset email (via POST /management/user/reset-password-url or
-// |POST /users/password-reset-url), the user receives an email with a reset link containing a JWT token.
-// |
-// |This endpoint accepts that token along with a new password and completes the password reset.
-// |
-// |The token is a signed JWT with a configurable expiry (default: 120 minutes).
-// |Configure the expiry with the property: password_reset_token_expiry_minutes
-// |
-// |Required fields:
-// |- token: The JWT reset token from the password reset email
-// |- new_password: The new password (must meet strong password requirements)
-// |
-// |The token is single-use. Once the password is reset, the token is invalidated.
-// |
-// |""".stripMargin,
-// PostResetPasswordCompleteJsonV600(
-// "a1b2c3d4e5f67890abcdef1234567890",
-// "NewStr0ng!Password"
-// ),
-// ResetPasswordCompleteResponseJsonV600(
-// "Password has been reset successfully."
-// ),
-// List(
-// InvalidJsonFormat,
-// InvalidStrongPasswordFormat,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List())
-// )
-//
-// lazy val resetPasswordComplete: OBPEndpoint = {
-// case "users" :: "password" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// postedData <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordCompleteJsonV600]}",
-// 400,
-// callContext
-// ) {
-// json.extract[PostResetPasswordCompleteJsonV600]
-// }
-// token = postedData.token.trim
-// _ <- Helper.booleanToFuture(s"$InvalidJsonFormat Token cannot be empty", cc = callContext) {
-// token.nonEmpty
-// }
-// // Validate password strength
-// _ <- Helper.booleanToFuture(ErrorMessages.InvalidStrongPasswordFormat, 400, callContext) {
-// fullPasswordValidation(postedData.new_password)
-// }
-// // Verify JWT signature
-// _ <- Helper.booleanToFuture(s"$UnknownError Invalid or expired reset token", 400, callContext) {
-// try {
-// CertificateUtil.verifywtWithHmacProtection(token)
-// } catch {
-// case _: Exception => false
-// }
-// }
-// // Check JWT expiration and extract subject (uniqueId)
-// uniqueId <- NewStyle.function.tryons(
-// s"$UnknownError Invalid or expired reset token",
-// 400,
-// callContext
-// ) {
-// val signedJWT = com.nimbusds.jwt.SignedJWT.parse(token)
-// val expiration = signedJWT.getJWTClaimsSet.getExpirationTime
-// if (expiration == null || expiration.before(new java.util.Date())) {
-// throw new Exception("Token has expired")
-// }
-// signedJWT.getJWTClaimsSet.getSubject
-// }
-// // Find user by uniqueId from JWT
-// authUserBox <- Future {
-// code.model.dataAccess.AuthUser.findUserByValidationToken(uniqueId)
-// }
-// user <- NewStyle.function.tryons(
-// s"$UnknownError Invalid or expired reset token",
-// 400,
-// callContext
-// ) {
-// authUserBox.openOrThrowException("User not found")
-// }
-// } yield {
-// // Set the new password
-// user.password.set(postedData.new_password)
-// // Reset the unique ID token to invalidate the reset link
-// user.uniqueId.set(java.util.UUID.randomUUID().toString.replace("-", ""))
-// user.save
-//
-// (
-// ResetPasswordCompleteResponseJsonV600("Password has been reset successfully."),
-// HttpCode.`201`(callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getWebUiProp,
-// implementedInApiVersion,
-// nameOf(getWebUiProp),
-// "GET",
-// "/webui-props/WEBUI_PROP_NAME",
-// "Get WebUiProp by Name",
-// s"""
-// |
-// |Get a single WebUiProp by name.
-// |
-// |Properties with names starting with "webui_" can be stored in the database and managed via API.
-// |
-// |**Data Sources:**
-// |
-// |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.
-// |
-// |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.
-// |
-// |**Response Fields:**
-// |
-// |* `name`: The property name
-// |* `value`: The property value
-// |* `webUiPropsId` (optional): UUID for database props, omitted for config props
-// |* `source`: Either "database" (editable via API) or "config" (read-only from config file)
-// |
-// |**Query Parameter:**
-// |
-// |* `active` (optional, boolean string, default: "false")
-// | - If `active=false` or omitted: Returns only explicit prop from the database (source="database")
-// | - If `active=true`: Returns explicit prop from database, or if not found, returns implicit (default) prop from configuration file (source="config")
-// |
-// |**Examples:**
-// |
-// |Get database-stored prop only:
-// |${getObpApiRoot}/v6.0.0/webui-props/webui_api_explorer_url
-// |
-// |Get database prop or fallback to default:
-// |${getObpApiRoot}/v6.0.0/webui-props/webui_api_explorer_url?active=true
-// |
-// |""",
-// EmptyBody,
-// WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), Some("config")),
-// List(
-// WebUiPropsNotFoundByName,
-// UnknownError
-// ),
-// List(apiTagWebUiProps)
-// )
-// lazy val getWebUiProp: OBPEndpoint = {
-// case "webui-props" :: webUiPropName :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props/$webUiPropName (SINGLE PROP) called ==========")
-// val active = ObpS.param("active").getOrElse("false")
-// for {
-// invalidMsg <- Future(s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """)
-// isActived <- NewStyle.function.tryons(invalidMsg, 400, cc.callContext) {
-// active.toBoolean
-// }
-// explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() }
-// explicitProp = explicitWebUiProps.find(_.name == webUiPropName)
-// result <- {
-// explicitProp match {
-// case Some(prop) =>
-// // Found in database
-// Future.successful(WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = Some("database")))
-// case None if isActived =>
-// // Not in database, check implicit props if active=true
-// val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs =>
-// WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = Some("default"), source = Some("config"))
-// )
-// val implicitProp = implicitWebUiProps.find(_.name == webUiPropName)
-// implicitProp match {
-// case Some(prop) => Future.successful(prop)
-// case None => Future.failed(new Exception(s"$WebUiPropsNotFoundByName Current WEBUI_PROP_NAME($webUiPropName)"))
-// }
-// case None =>
-// // Not in database and active=false
-// Future.failed(new Exception(s"$WebUiPropsNotFoundByName Current WEBUI_PROP_NAME($webUiPropName)"))
-// }
-// }
-// } yield {
-// (result, HttpCode.`200`(cc.callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getWebUiProps,
-// implementedInApiVersion,
-// nameOf(getWebUiProps),
-// "GET",
-// "/webui-props",
-// "Get WebUiProps",
-// s"""
-// |
-// |Get WebUiProps - properties that configure the Web UI behavior and appearance.
-// |
-// |Properties with names starting with "webui_" can be stored in the database and managed via API.
-// |
-// |**Data Sources:**
-// |
-// |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.
-// |
-// |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.
-// |
-// |**Response Fields:**
-// |
-// |* `name`: The property name
-// |* `value`: The property value
-// |* `webUiPropsId` (optional): UUID for database props, omitted for config props
-// |* `source`: Either "database" (editable via API) or "config" (read-only from config file)
-// |
-// |**Query Parameter:**
-// |
-// |* `what` (optional, string, default: "active")
-// | - `active`: Returns one value per property name
-// | - If property exists in database: returns database value (source="database")
-// | - If property only in config file: returns config default value (source="config")
-// | - `database`: Returns ONLY properties explicitly stored in the database (source="database")
-// | - `config`: Returns ONLY default properties from configuration file (source="config")
-// |
-// |**Examples:**
-// |
-// |Get active props (database overrides config, one value per prop):
-// |${getObpApiRoot}/v6.0.0/webui-props
-// |${getObpApiRoot}/v6.0.0/webui-props?what=active
-// |
-// |Get only database-stored props:
-// |${getObpApiRoot}/v6.0.0/webui-props?what=database
-// |
-// |Get only default props from configuration:
-// |${getObpApiRoot}/v6.0.0/webui-props?what=config
-// |
-// |For more details about WebUI Props, including how to set config file defaults and precedence order, see ${Glossary.getGlossaryItemLink("webui_props")}.
-// |
-// |""",
-// EmptyBody,
-// ListResult(
-// "webui_props",
-// (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), Some("database"))))
-// )
-// ,
-// List(
-// UnknownError
-// ),
-// List(apiTagWebUiProps)
-// )
-//
-//
-// lazy val getWebUiProps: OBPEndpoint = {
-// case "webui-props":: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// val what = ObpS.param("what").getOrElse("active")
-// logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props (ALL PROPS) called with what=$what ==========")
-// for {
-// callContext <- Future.successful(cc.callContext)
-// _ <- NewStyle.function.tryons(s"""$InvalidFilterParameterFormat `what` must be one of: active, database, config. Current value: $what""", 400, callContext) {
-// what match {
-// case "active" | "database" | "config" => true
-// case _ => false
-// }
-// }
-// explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() }
-// explicitWebUiPropsWithSource = explicitWebUiProps.map(prop => WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = Some("database")))
-// implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = Some("default"), source = Some("config")))
-// result = what match {
-// case "database" =>
-// // Return only database props
-// explicitWebUiPropsWithSource
-// case "config" =>
-// // Return only config file props
-// implicitWebUiProps.distinct
-// case "active" =>
-// // Return one value per prop: database value if exists, otherwise config value
-// val databasePropNames = explicitWebUiPropsWithSource.map(_.name).toSet
-// val configPropsNotInDatabase = implicitWebUiProps.distinct.filterNot(prop => databasePropNames.contains(prop.name))
-// explicitWebUiPropsWithSource ++ configPropsNotInDatabase
-// }
-// } yield {
-// logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props returning ${result.size} records ==========")
-// result.foreach { prop =>
-// logger.info(s" - name: ${prop.name}, value: ${prop.value}, webUiPropsId: ${prop.webUiPropsId}")
-// }
-// logger.info(s"========== END GET /obp/${ApiVersion.v6_0_0}/webui-props ==========")
-// (ListResult("webui_props", result), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateWebUiProps,
-// implementedInApiVersion,
-// nameOf(createOrUpdateWebUiProps),
-// "PUT",
-// "/management/webui_props/WEBUI_PROP_NAME",
-// "Create or Update WebUiProps",
-// s"""Create or Update a WebUiProps.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |This endpoint is idempotent - it will create the property if it doesn't exist, or update it if it does.
-// |The property is identified by WEBUI_PROP_NAME in the URL path.
-// |
-// |Explanation of Fields:
-// |
-// |* WEBUI_PROP_NAME in URL path (must start with `webui_`, contain only alphanumeric characters, underscore, and dot, not exceed 255 characters, and will be converted to lowercase)
-// |* value is required String value in request body
-// |
-// |The line break and double quotations should be escaped, example:
-// |
-// |```
-// |
-// |{"name": "webui_some", "value": "this value
-// |have "line break" and double quotations."}
-// |
-// |```
-// |should be escaped like this:
-// |
-// |```
-// |
-// |{"name": "webui_some", "value": "this value\\nhave \\"line break\\" and double quotations."}
-// |
-// |```
-// |
-// |Insert image examples:
-// |
-// |```
-// |// set width=100 and height=50
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |// only set height=50
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |// only width=20%
-// |{"name": "webui_some_pic", "value": "here is a picture "}
-// |
-// |```
-// |
-// |""",
-// WebUiPropsPutJsonV600("https://apiexplorer.openbankproject.com"),
-// WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("some-web-ui-props-id")),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// InvalidWebUiProps,
-// UnknownError
-// ),
-// List(apiTagWebUiProps),
-// Some(List(canCreateWebUiProps))
-// )
-//
-// lazy val createOrUpdateWebUiProps: OBPEndpoint = {
-// case "management" :: "webui_props" :: webUiPropName :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateWebUiProps, callContext)
-// // Convert name to lowercase
-// webUiPropNameLower = webUiPropName.toLowerCase
-// invalidMsg = s"""$InvalidWebUiProps name must start with webui_, but current name is: ${webUiPropNameLower} """
-// _ <- NewStyle.function.tryons(invalidMsg, 400, callContext) {
-// require(webUiPropNameLower.startsWith("webui_"))
-// }
-// invalidCharsMsg = s"""$InvalidWebUiProps name must contain only alphanumeric characters, underscore, and dot. Current name: ${webUiPropNameLower} """
-// _ <- NewStyle.function.tryons(invalidCharsMsg, 400, callContext) {
-// require(webUiPropNameLower.matches("^[a-zA-Z0-9_.]+$"))
-// }
-// invalidLengthMsg = s"""$InvalidWebUiProps name must not exceed 255 characters. Current length: ${webUiPropNameLower.length} """
-// _ <- NewStyle.function.tryons(invalidLengthMsg, 400, callContext) {
-// require(webUiPropNameLower.length <= 255)
-// }
-// // Check if resource already exists to determine status code
-// existingProp <- Future { MappedWebUiPropsProvider.getByName(webUiPropNameLower) }
-// resourceExists = existingProp.isDefined
-// failMsg = s"$InvalidJsonFormat The Json body should contain a value field"
-// valueJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[WebUiPropsPutJsonV600]
-// }
-// webUiPropsData = WebUiPropsCommons(webUiPropNameLower, valueJson.value)
-// Full(webUiProps) <- Future { MappedWebUiPropsProvider.createOrUpdate(webUiPropsData) }
-// } yield {
-// val commonsData: WebUiPropsCommons = webUiProps
-// val statusCode = if (resourceExists) HttpCode.`200`(callContext) else HttpCode.`201`(callContext)
-// (commonsData, statusCode)
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteWebUiProps,
-// implementedInApiVersion,
-// nameOf(deleteWebUiProps),
-// "DELETE",
-// "/management/webui_props/WEBUI_PROP_NAME",
-// "Delete WebUiProps",
-// s"""Delete a WebUiProps specified by WEBUI_PROP_NAME.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |The property name will be converted to lowercase before deletion.
-// |
-// |Returns 204 No Content on successful deletion.
-// |
-// |This endpoint is idempotent - if the property does not exist, it still returns 204 No Content.
-// |
-// |Requires the $canDeleteWebUiProps role.
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidWebUiProps,
-// UnknownError
-// ),
-// List(apiTagWebUiProps),
-// Some(List(canDeleteWebUiProps))
-// )
-//
-// lazy val deleteWebUiProps: OBPEndpoint = {
-// case "management" :: "webui_props" :: webUiPropName :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteWebUiProps, callContext)
-// // Convert name to lowercase
-// webUiPropNameLower = webUiPropName.toLowerCase
-// invalidMsg = s"""$InvalidWebUiProps name must start with webui_, but current name is: ${webUiPropNameLower} """
-// _ <- NewStyle.function.tryons(invalidMsg, 400, callContext) {
-// require(webUiPropNameLower.startsWith("webui_"))
-// }
-// invalidCharsMsg = s"""$InvalidWebUiProps name must contain only alphanumeric characters, underscore, and dot. Current name: ${webUiPropNameLower} """
-// _ <- NewStyle.function.tryons(invalidCharsMsg, 400, callContext) {
-// require(webUiPropNameLower.matches("^[a-zA-Z0-9_.]+$"))
-// }
-// invalidLengthMsg = s"""$InvalidWebUiProps name must not exceed 255 characters. Current length: ${webUiPropNameLower.length} """
-// _ <- NewStyle.function.tryons(invalidLengthMsg, 400, callContext) {
-// require(webUiPropNameLower.length <= 255)
-// }
-// // Check if resource exists
-// existingProp <- Future { MappedWebUiPropsProvider.getByName(webUiPropNameLower) }
-// _ <- existingProp match {
-// case Full(prop) =>
-// // Property exists - delete it
-// Future { MappedWebUiPropsProvider.delete(prop.webUiPropsId.getOrElse("")) } map {
-// case Full(true) => Full(())
-// case Full(false) => ObpApiFailure(s"$UnknownError Cannot delete WebUI prop", 500, callContext)
-// case Empty => ObpApiFailure(s"$UnknownError Cannot delete WebUI prop", 500, callContext)
-// case Failure(msg, _, _) => ObpApiFailure(msg, 500, callContext)
-// }
-// case Empty =>
-// // Property not found - idempotent delete returns success
-// Future.successful(Full(()))
-// case Failure(msg, _, _) =>
-// Future.failed(new Exception(msg))
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSystemDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getSystemDynamicEntities),
-// "GET",
-// "/management/system-dynamic-entities",
-// "Get System Dynamic Entities",
-// s"""Get all System Dynamic Entities with record counts.
-// |
-// |Each dynamic entity in the response includes a `record_count` field showing how many data records exist for that entity.
-// |
-// |This v6.0.0 endpoint returns snake_case field names and an explicit `entity_name` field.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )} """,
-// EmptyBody,
-// DynamicEntitiesWithCountJsonV600(
-// dynamic_entities = List(
-// DynamicEntityDefinitionWithCountJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[org.json4s.JsonAST.JObject],
-// record_count = 42
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canGetSystemLevelDynamicEntities))
-// )
-//
-// lazy val getSystemDynamicEntities: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntities(None, false)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities.sortBy(_.entityName)
-// val entitiesWithCounts = listCommons.map { entity =>
-// val recordCount = DynamicData.count(
-// By(DynamicData.DynamicEntityName, entity.entityName),
-// By(DynamicData.IsPersonalEntity, false),
-// if (entity.bankId.isEmpty) NullRef(DynamicData.BankId) else By(DynamicData.BankId, entity.bankId.get)
-// )
-// (entity, recordCount)
-// }
-// (
-// JSONFactory600.createDynamicEntitiesWithCountJson(entitiesWithCounts),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getBankLevelDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getBankLevelDynamicEntities),
-// "GET",
-// "/management/banks/BANK_ID/dynamic-entities",
-// "Get Bank Level Dynamic Entities",
-// s"""Get all Bank Level Dynamic Entities for one bank with record counts.
-// |
-// |Each dynamic entity in the response includes a `record_count` field showing how many data records exist for that entity.
-// |
-// |This v6.0.0 endpoint returns snake_case field names and an explicit `entity_name` field.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )} """,
-// EmptyBody,
-// DynamicEntitiesWithCountJsonV600(
-// dynamic_entities = List(
-// DynamicEntityDefinitionWithCountJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = Some("gh.29.uk"),
-// has_personal_entity = true,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[org.json4s.JsonAST.JObject],
-// record_count = 42
-// )
-// )
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities))
-// )
-//
-// lazy val getBankLevelDynamicEntities: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: Nil JsonGet req => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntities(Some(bankId), false)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities.sortBy(_.entityName)
-// val entitiesWithCounts = listCommons.map { entity =>
-// val recordCount = DynamicData.count(
-// By(DynamicData.DynamicEntityName, entity.entityName),
-// By(DynamicData.IsPersonalEntity, false),
-// By(DynamicData.BankId, bankId)
-// )
-// (entity, recordCount)
-// }
-// (
-// JSONFactory600.createDynamicEntitiesWithCountJson(entitiesWithCounts),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// private def unboxResult[T: Manifest](box: Box[T], entityName: String): T = {
-// if (box.isInstanceOf[Failure]) {
-// val failure = box.asInstanceOf[Failure]
-// // change the internal db column name 'dynamicdataid' to entity's id name
-// val msg = failure.msg.replace(
-// DynamicData.DynamicDataId.dbColumnName,
-// StringUtils.uncapitalize(entityName) + "Id"
-// )
-// val changedMsgFailure = failure.copy(msg = s"$InternalServerError $msg")
-// fullBoxOrException[T](changedMsgFailure)
-// }
-// box.openOrThrowException(s"$UnknownError ")
-// }
-//
-// // Helper method for creating dynamic entities with v6.0.0 response format
-// private def createDynamicEntityV600(
-// cc: CallContext,
-// dynamicEntity: DynamicEntityCommons
-// ) = {
-// for {
-// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity(
-// dynamicEntity,
-// cc.callContext
-// )
-// // Grant the CRUD roles to the logged-in user
-// crudRoles = List(
-// DynamicEntityInfo.canCreateRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo.canUpdateRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo.canGetRole(result.entityName, dynamicEntity.bankId),
-// DynamicEntityInfo.canDeleteRole(result.entityName, dynamicEntity.bankId)
-// )
-// } yield {
-// crudRoles.map(role =>
-// Entitlement.entitlement.vend.addEntitlement(
-// dynamicEntity.bankId.getOrElse(""),
-// cc.userId,
-// role.toString()
-// )
-// )
-// val commonsData: DynamicEntityCommons = result
-// (
-// JSONFactory600.createMyDynamicEntitiesJson(List(commonsData)).dynamic_entities.head,
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-//
-// // Helper method for updating dynamic entities with v6.0.0 response format
-// private def updateDynamicEntityV600(
-// cc: CallContext,
-// dynamicEntity: DynamicEntityCommons
-// ) = {
-// for {
-// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity(
-// dynamicEntity,
-// cc.callContext
-// )
-// } yield {
-// val commonsData: DynamicEntityCommons = result
-// (
-// JSONFactory600.createMyDynamicEntitiesJson(List(commonsData)).dynamic_entities.head,
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(createSystemDynamicEntity),
-// "POST",
-// "/management/system-dynamic-entities",
-// "Create System Level Dynamic Entity",
-// s"""Create a system level Dynamic Entity.
-// |
-// |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.
-// |
-// |**Request format:**
-// |```json
-// |{
-// | "entity_name": "customer_preferences",
-// | "has_personal_entity": true,
-// | "has_public_access": false,
-// | "has_community_access": false,
-// | "personal_requires_role": false,
-// | "schema": {
-// | "description": "User preferences",
-// | "required": ["theme"],
-// | "properties": {
-// | "theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"},
-// | "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}
-// | }
-// | }
-// |}
-// |```
-// |
-// |**Note:**
-// |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.
-// |* Each property MUST include an `example` field with a valid example value.
-// |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.
-// |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.
-// |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).
-// |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}""",
-// CreateDynamicEntityRequestJsonV600(
-// entity_name = "customer_preferences",
-// has_personal_entity = Some(true),
-// has_public_access = Some(false),
-// has_community_access = Some(false),
-// personal_requires_role = Some(false),
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// has_public_access = false,
-// has_community_access = false,
-// personal_requires_role = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canCreateSystemLevelDynamicEntity)),
-// authMode = UserOrApplication
-// )
-//
-// // v6.0.0 entity names must be lowercase with underscores (snake_case)
-// private val validEntityNamePattern = "^[a-z][a-z0-9_]*$".r.pattern
-//
-// private def validateEntityNameV600(entityName: String, callContext: Option[CallContext]): Future[Unit] = {
-// if (validEntityNamePattern.matcher(entityName).matches()) {
-// Future.successful(())
-// } else {
-// Future.failed(new RuntimeException(s"$InvalidDynamicEntityName Current value: '$entityName'"))
-// }
-// }
-//
-// lazy val createSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// request <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[CreateDynamicEntityRequestJsonV600]
-// }
-// _ <- validateEntityNameV600(request.entity_name, cc.callContext)
-// internalJson = JSONFactory600.convertV600RequestToInternal(request)
-// dynamicEntity = DynamicEntityCommons(internalJson, None, cc.userId, None)
-// result <- createDynamicEntityV600(cc, dynamicEntity)
-// } yield result
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(createBankLevelDynamicEntity),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-entities",
-// "Create Bank Level Dynamic Entity",
-// s"""Create a bank level Dynamic Entity.
-// |
-// |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.
-// |
-// |**Request format:**
-// |```json
-// |{
-// | "entity_name": "customer_preferences",
-// | "has_personal_entity": true,
-// | "has_public_access": false,
-// | "has_community_access": false,
-// | "personal_requires_role": false,
-// | "schema": {
-// | "description": "User preferences",
-// | "required": ["theme"],
-// | "properties": {
-// | "theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"},
-// | "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}
-// | }
-// | }
-// |}
-// |```
-// |
-// |**Note:**
-// |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.
-// |* Each property MUST include an `example` field with a valid example value.
-// |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.
-// |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.
-// |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).
-// |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}""",
-// CreateDynamicEntityRequestJsonV600(
-// entity_name = "customer_preferences",
-// has_personal_entity = Some(true),
-// has_public_access = Some(false),
-// has_community_access = Some(false),
-// personal_requires_role = Some(false),
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = Some("gh.29.uk"),
-// has_personal_entity = true,
-// has_public_access = false,
-// has_community_access = false,
-// personal_requires_role = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canCreateBankLevelDynamicEntity, canCreateAnyBankLevelDynamicEntity))
-// )
-//
-// lazy val createBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: Nil JsonPost json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// request <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[CreateDynamicEntityRequestJsonV600]
-// }
-// _ <- validateEntityNameV600(request.entity_name, cc.callContext)
-// internalJson = JSONFactory600.convertV600RequestToInternal(request)
-// dynamicEntity = DynamicEntityCommons(internalJson, None, cc.userId, Some(bankId))
-// result <- createDynamicEntityV600(cc, dynamicEntity)
-// } yield result
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateSystemDynamicEntity),
-// "PUT",
-// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update System Level Dynamic Entity",
-// s"""Update a system level Dynamic Entity.
-// |
-// |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.
-// |
-// |**Request format:**
-// |```json
-// |{
-// | "entity_name": "customer_preferences",
-// | "has_personal_entity": true,
-// | "has_public_access": false,
-// | "has_community_access": false,
-// | "personal_requires_role": false,
-// | "schema": {
-// | "description": "User preferences updated",
-// | "required": ["theme"],
-// | "properties": {
-// | "theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"},
-// | "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"},
-// | "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}
-// | }
-// | }
-// |}
-// |```
-// |
-// |**Note:**
-// |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.
-// |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.
-// |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.
-// |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).
-// |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}""",
-// UpdateDynamicEntityRequestJsonV600(
-// entity_name = "customer_preferences",
-// has_personal_entity = Some(true),
-// has_public_access = Some(false),
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// has_public_access = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canUpdateSystemDynamicEntity))
-// )
-//
-// lazy val updateSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// request <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateDynamicEntityRequestJsonV600]
-// }
-// _ <- validateEntityNameV600(request.entity_name, cc.callContext)
-// internalJson = JSONFactory600.convertV600UpdateRequestToInternal(request)
-// dynamicEntity = DynamicEntityCommons(internalJson, Some(dynamicEntityId), cc.userId, None)
-// result <- updateDynamicEntityV600(cc, dynamicEntity)
-// } yield result
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateBankLevelDynamicEntity),
-// "PUT",
-// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update Bank Level Dynamic Entity",
-// s"""Update a bank level Dynamic Entity.
-// |
-// |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.
-// |
-// |**Request format:**
-// |```json
-// |{
-// | "entity_name": "customer_preferences",
-// | "has_personal_entity": true,
-// | "has_public_access": false,
-// | "has_community_access": false,
-// | "personal_requires_role": false,
-// | "schema": {
-// | "description": "User preferences updated",
-// | "required": ["theme"],
-// | "properties": {
-// | "theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"},
-// | "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"},
-// | "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}
-// | }
-// | }
-// |}
-// |```
-// |
-// |**Note:**
-// |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.
-// |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.
-// |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.
-// |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).
-// |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}""",
-// UpdateDynamicEntityRequestJsonV600(
-// entity_name = "customer_preferences",
-// has_personal_entity = Some(true),
-// has_public_access = Some(false),
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = Some("gh.29.uk"),
-// has_personal_entity = true,
-// has_public_access = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $BankNotFound,
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canUpdateBankLevelDynamicEntity))
-// )
-//
-// lazy val updateBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// request <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateDynamicEntityRequestJsonV600]
-// }
-// _ <- validateEntityNameV600(request.entity_name, cc.callContext)
-// internalJson = JSONFactory600.convertV600UpdateRequestToInternal(request)
-// dynamicEntity = DynamicEntityCommons(internalJson, Some(dynamicEntityId), cc.userId, Some(bankId))
-// result <- updateDynamicEntityV600(cc, dynamicEntity)
-// } yield result
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateMyDynamicEntity,
-// implementedInApiVersion,
-// nameOf(updateMyDynamicEntity),
-// "PUT",
-// "/my/dynamic-entities/DYNAMIC_ENTITY_ID",
-// "Update My Dynamic Entity",
-// s"""Update a Dynamic Entity that I created.
-// |
-// |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.
-// |
-// |**Request format:**
-// |```json
-// |{
-// | "entity_name": "customer_preferences",
-// | "has_personal_entity": true,
-// | "has_public_access": false,
-// | "has_community_access": false,
-// | "personal_requires_role": false,
-// | "schema": {
-// | "description": "User preferences updated",
-// | "required": ["theme"],
-// | "properties": {
-// | "theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"},
-// | "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"},
-// | "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}
-// | }
-// | }
-// |}
-// |```
-// |
-// |**Note:**
-// |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.
-// |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.
-// |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.
-// |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).
-// |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("My-Dynamic-Entities")}""",
-// UpdateDynamicEntityRequestJsonV600(
-// entity_name = "customer_preferences",
-// has_personal_entity = Some(true),
-// has_public_access = Some(false),
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// has_public_access = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences updated", "required": ["theme"], "properties": {"theme": {"type": "string", "minLength": 1, "maxLength": 20, "example": "dark", "description": "The UI theme preference"}, "language": {"type": "string", "minLength": 2, "maxLength": 5, "example": "en", "description": "ISO language code"}, "notifications_enabled": {"type": "boolean", "example": "true", "description": "Whether to send notifications"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi)
-// )
-//
-// lazy val updateMyDynamicEntity: OBPEndpoint = {
-// case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// // Verify the user owns this dynamic entity
-// existingEntity <- Future(
-// NewStyle.function.getDynamicEntitiesByUserId(cc.userId).find(_.dynamicEntityId.contains(dynamicEntityId))
-// )
-// _ <- Helper.booleanToFuture(s"$DynamicEntityNotFoundByDynamicEntityId dynamicEntityId = $dynamicEntityId", cc = cc.callContext) {
-// existingEntity.isDefined
-// }
-// request <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateDynamicEntityRequestJsonV600]
-// }
-// _ <- validateEntityNameV600(request.entity_name, cc.callContext)
-// internalJson = JSONFactory600.convertV600UpdateRequestToInternal(request)
-// dynamicEntity = DynamicEntityCommons(internalJson, Some(dynamicEntityId), cc.userId, existingEntity.get.bankId)
-// result <- updateDynamicEntityV600(cc, dynamicEntity)
-// } yield result
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSystemDynamicEntityCascade,
-// implementedInApiVersion,
-// nameOf(deleteSystemDynamicEntityCascade),
-// "DELETE",
-// "/management/system-dynamic-entities/cascade/DYNAMIC_ENTITY_ID",
-// "Delete System Level Dynamic Entity Cascade",
-// s"""Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID and all its data records.
-// |
-// |This endpoint performs a cascade delete:
-// |1. Automatically backs up the entity definition and all data records to a ZZ_BAK_ prefixed entity (e.g. my_entity is backed up to ZZ_BAK_my_entity). If a previous ZZ_BAK_ backup exists, it is overwritten.
-// |2. Deletes all data records associated with the dynamic entity
-// |3. Deletes the dynamic entity definition itself
-// |
-// |Note: Entities whose name already starts with ZZ_BAK_ are not backed up again (to avoid infinite backup chains).
-// |
-// |This operation is only allowed for non-personal entities (hasPersonalEntity=false).
-// |For personal entities (hasPersonalEntity=true), you must delete the records and definition separately.
-// |
-// |
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "Dynamic-Entities"
-// )}/
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canDeleteCascadeSystemDynamicEntity))
-// )
-// lazy val deleteSystemDynamicEntityCascade: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: "cascade" :: dynamicEntityId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// deleteDynamicEntityCascadeMethod(None, dynamicEntityId, cc)
-// }
-// }
-//
-// private def backupDynamicEntity(
-// entity: DynamicEntityT,
-// backupName: String,
-// dataRecords: JArray
-// ): Unit = {
-// // Clean up any existing backup
-// DynamicEntityProvider.connectorMethodProvider.vend
-// .getByEntityName(entity.bankId, backupName).foreach { existingBackup =>
-// // Delete old backup data
-// DynamicDataProvider.connectorMethodProvider.vend
-// .getAll(entity.bankId, backupName, None, false)
-// .foreach { record =>
-// DynamicDataProvider.connectorMethodProvider.vend.delete(
-// entity.bankId, backupName, record.dynamicDataId.getOrElse(""), None, false
-// )
-// }
-// // Delete old backup definition
-// DynamicEntityProvider.connectorMethodProvider.vend.delete(existingBackup)
-// }
-//
-// // Create backup entity definition (rename top-level key in metadataJson)
-// val originalMetadata = json.parse(entity.metadataJson).asInstanceOf[JObject]
-// val backupMetadata = JObject(originalMetadata.obj.map {
-// case JField(name, value) if name == entity.entityName => JField(backupName, value)
-// case other => other
-// })
-// val backupEntity = DynamicEntityCommons(
-// entityName = backupName,
-// metadataJson = json.compactRender(backupMetadata),
-// dynamicEntityId = None,
-// userId = entity.userId,
-// bankId = entity.bankId,
-// hasPersonalEntity = entity.hasPersonalEntity
-// )
-// DynamicEntityProvider.connectorMethodProvider.vend.createOrUpdate(backupEntity)
-//
-// // Copy data records
-// val originalIdField = DynamicEntityHelper.createEntityId(entity.entityName)
-// val backupIdField = DynamicEntityHelper.createEntityId(backupName)
-// dataRecords.arr.foreach { record =>
-// val recordObj = record.asInstanceOf[JObject]
-// val transformedFields = recordObj.obj.map {
-// case JField(name, _) if name == originalIdField =>
-// JField(backupIdField, JString(java.util.UUID.randomUUID().toString))
-// case other => other
-// }
-// DynamicDataProvider.connectorMethodProvider.vend.save(
-// entity.bankId, backupName, JObject(transformedFields),
-// Some(entity.userId), entity.hasPersonalEntity
-// )
-// }
-// }
-//
-// private def deleteDynamicEntityCascadeMethod(
-// bankId: Option[String],
-// dynamicEntityId: String,
-// cc: CallContext
-// ) = {
-// for {
-// // Get the dynamic entity
-// (entity, _) <- NewStyle.function.getDynamicEntityById(
-// bankId,
-// dynamicEntityId,
-// cc.callContext
-// )
-// // Check if this is a personal entity - cascade delete not allowed for personal entities
-// _ <- Helper.booleanToFuture(failMsg = CannotDeleteCascadePersonalEntity, cc = cc.callContext) {
-// !entity.hasPersonalEntity
-// }
-// // Get all data records for this entity
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// entity.entityName,
-// None,
-// None,
-// entity.bankId,
-// None,
-// None,
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// entity.entityName
-// )
-// // Backup entity and data before deletion (skip if already a backup entity)
-// _ <- Future {
-// if (!entity.entityName.startsWith("ZZ_BAK_")) {
-// backupDynamicEntity(entity, s"ZZ_BAK_${entity.entityName}", resultList)
-// }
-// }
-// // Delete all data records
-// _ <- Future.sequence {
-// resultList.arr.map { record =>
-// val idFieldName = DynamicEntityHelper.createEntityId(entity.entityName)
-// val recordId = (record \ idFieldName).asInstanceOf[JString].s
-// Future {
-// DynamicDataProvider.connectorMethodProvider.vend.delete(
-// entity.bankId,
-// entity.entityName,
-// recordId,
-// None,
-// false
-// )
-// }
-// }
-// }
-// // Delete the dynamic entity definition
-// deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity(
-// bankId,
-// dynamicEntityId
-// )
-// } yield {
-// (deleted, HttpCode.`200`(cc.callContext))
-// }
-// }
-//
-// // ABAC Rule Endpoints
-// staticResourceDocs += ResourceDoc(
-// createAbacRule,
-// implementedInApiVersion,
-// nameOf(createAbacRule),
-// "POST",
-// "/management/abac-rules",
-// "Create ABAC Rule",
-// s"""Create a new ABAC (Attribute-Based Access Control) rule.
-// |
-// |ABAC rules are Scala functions that return a Boolean value indicating whether access should be granted.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |- ${Glossary.getGlossaryItemLink("ABAC_Testing_Examples")} - Testing examples and patterns
-// |
-// |The rule function receives 18 parameters including authenticatedUser, attributes, auth context, and optional objects (bank, account, transaction, etc.).
-// |
-// |Example rule code:
-// |```scala
-// |// Allow access only if authenticated user is admin
-// |authenticatedUser.emailAddress.contains("admin")
-// |```
-// |
-// |```scala
-// |// Allow access only to accounts with balance > 1000
-// |accountOpt.exists(_.balance.toDouble > 1000.0)
-// |```
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// CreateAbacRuleJsonV600(
-// rule_name = "admin_only",
-// rule_code = """user.emailAddress.contains("admin")""",
-// description = "Only allow access to users with admin email",
-// policy = "user-access,admin",
-// is_active = true
-// ),
-// AbacRuleJsonV600(
-// abac_rule_id = "abc123",
-// rule_name = "admin_only",
-// rule_code = """user.emailAddress.contains("admin")""",
-// is_active = true,
-// description = "Only allow access to users with admin email",
-// policy = "user-access,admin",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user123"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canCreateAbacRule))
-// )
-//
-// lazy val createAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canCreateAbacRule, callContext)
-// createJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) {
-// json.extract[CreateAbacRuleJsonV600]
-// }
-// _ <- NewStyle.function.tryons(s"Rule name must not be empty", 400, callContext) {
-// createJson.rule_name.nonEmpty
-// }
-// _ <- NewStyle.function.tryons(s"Rule code must not be empty", 400, callContext) {
-// createJson.rule_code.nonEmpty
-// }
-// // Validate rule code by attempting to compile it (includes statistical permissiveness check)
-// _ <- AbacRuleEngine.validateRuleCodeAsync(createJson.rule_code) map {
-// unboxFullOrFail(_, callContext, s"Invalid ABAC rule code", 400)
-// }
-// rule <- Future {
-// MappedAbacRuleProvider.createAbacRule(
-// ruleName = createJson.rule_name,
-// ruleCode = createJson.rule_code,
-// description = createJson.description,
-// policy = createJson.policy,
-// isActive = createJson.is_active,
-// createdBy = user.userId
-// )
-// } map {
-// unboxFullOrFail(_, callContext, s"Could not create ABAC rule", 400)
-// }
-// } yield {
-// (createAbacRuleJsonV600(rule), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAbacRule,
-// implementedInApiVersion,
-// nameOf(getAbacRule),
-// "GET",
-// "/management/abac-rules/ABAC_RULE_ID",
-// "Get ABAC Rule",
-// s"""Get an ABAC rule by its ID.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// AbacRuleJsonV600(
-// abac_rule_id = "abc123",
-// rule_name = "admin_only",
-// rule_code = """user.emailAddress.contains("admin")""",
-// is_active = true,
-// description = "Only allow access to users with admin email",
-// policy = "user-access,admin",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user123"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canGetAbacRule))
-// )
-//
-// lazy val getAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: ruleId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetAbacRule, callContext)
-// rule <- Future {
-// MappedAbacRuleProvider.getAbacRuleById(ruleId)
-// } map {
-// unboxFullOrFail(_, callContext, s"ABAC Rule not found with ID: $ruleId", 404)
-// }
-// } yield {
-// (createAbacRuleJsonV600(rule), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAbacRules,
-// implementedInApiVersion,
-// nameOf(getAbacRules),
-// "GET",
-// "/management/abac-rules",
-// "Get ABAC Rules",
-// s"""Get all ABAC rules.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// AbacRulesJsonV600(
-// abac_rules = List(
-// AbacRuleJsonV600(
-// abac_rule_id = "abc123",
-// rule_name = "admin_only",
-// rule_code = """user.emailAddress.contains("admin")""",
-// is_active = true,
-// description = "Only allow access to users with admin email",
-// policy = "user-access,admin",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user123"
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canGetAbacRule))
-// )
-//
-// lazy val getAbacRules: OBPEndpoint = {
-// case "management" :: "abac-rules" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetAbacRule, callContext)
-// rules <- Future {
-// MappedAbacRuleProvider.getAllAbacRules()
-// }
-// } yield {
-// (createAbacRulesJsonV600(rules), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAbacRulesByPolicy,
-// implementedInApiVersion,
-// nameOf(getAbacRulesByPolicy),
-// "GET",
-// "/management/abac-rules/policy/POLICY",
-// "Get ABAC Rules by Policy",
-// s"""Get all ABAC rules that belong to a specific policy.
-// |
-// |Multiple rules can share the same policy. Rules with multiple policies (comma-separated)
-// |will be returned if any of their policies match the requested policy.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// AbacRulesJsonV600(
-// abac_rules = List(
-// AbacRuleJsonV600(
-// abac_rule_id = "abc123",
-// rule_name = "admin_only",
-// rule_code = """user.emailAddress.contains("admin")""",
-// is_active = true,
-// description = "Only allow access to users with admin email",
-// policy = "user-access,admin",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user123"
-// ),
-// AbacRuleJsonV600(
-// abac_rule_id = "def456",
-// rule_name = "admin_department_check",
-// rule_code = """user.department == "admin"""",
-// is_active = true,
-// description = "Check if user is in admin department",
-// policy = "admin",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user123"
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canGetAbacRule))
-// )
-//
-// lazy val getAbacRulesByPolicy: OBPEndpoint = {
-// case "management" :: "abac-rules" :: "policy" :: policy :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetAbacRule, callContext)
-// rules <- Future {
-// MappedAbacRuleProvider.getAbacRulesByPolicy(policy)
-// }
-// } yield {
-// (createAbacRulesJsonV600(rules), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateAbacRule,
-// implementedInApiVersion,
-// nameOf(updateAbacRule),
-// "PUT",
-// "/management/abac-rules/ABAC_RULE_ID",
-// "Update ABAC Rule",
-// s"""Update an existing ABAC rule.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// UpdateAbacRuleJsonV600(
-// rule_name = "admin_only_updated",
-// rule_code = """user.emailAddress.contains("admin") && user.provider == "obp"""",
-// description = "Only allow access to OBP admin users",
-// policy = "user-access,admin,obp",
-// is_active = true
-// ),
-// AbacRuleJsonV600(
-// abac_rule_id = "abc123",
-// rule_name = "admin_only_updated",
-// rule_code = """user.emailAddress.contains("admin") && user.provider == "obp"""",
-// is_active = true,
-// description = "Only allow access to OBP admin users",
-// policy = "user-access,admin,obp",
-// created_by_user_id = "user123",
-// updated_by_user_id = "user456"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canUpdateAbacRule))
-// )
-//
-// lazy val updateAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: ruleId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canUpdateAbacRule, callContext)
-// updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) {
-// json.extract[UpdateAbacRuleJsonV600]
-// }
-// // Validate rule code by attempting to compile it (includes statistical permissiveness check)
-// _ <- AbacRuleEngine.validateRuleCodeAsync(updateJson.rule_code) map {
-// unboxFullOrFail(_, callContext, s"Invalid ABAC rule code", 400)
-// }
-// rule <- Future {
-// MappedAbacRuleProvider.updateAbacRule(
-// ruleId = ruleId,
-// ruleName = updateJson.rule_name,
-// ruleCode = updateJson.rule_code,
-// description = updateJson.description,
-// policy = updateJson.policy,
-// isActive = updateJson.is_active,
-// updatedBy = user.userId
-// )
-// } map {
-// unboxFullOrFail(_, callContext, s"Could not update ABAC rule with ID: $ruleId", 400)
-// }
-// // Clear rule from cache after update
-// _ <- Future {
-// AbacRuleEngine.clearRuleFromCache(ruleId)
-// }
-// } yield {
-// (createAbacRuleJsonV600(rule), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteAbacRule,
-// implementedInApiVersion,
-// nameOf(deleteAbacRule),
-// "DELETE",
-// "/management/abac-rules/ABAC_RULE_ID",
-// "Delete ABAC Rule",
-// s"""Delete an ABAC rule by its ID.
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canDeleteAbacRule))
-// )
-//
-// lazy val deleteAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: ruleId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canDeleteAbacRule, callContext)
-// deleted <- Future {
-// MappedAbacRuleProvider.deleteAbacRule(ruleId)
-// } map {
-// unboxFullOrFail(_, callContext, s"Could not delete ABAC rule with ID: $ruleId", 400)
-// }
-// // Clear rule from cache after deletion
-// _ <- Future {
-// AbacRuleEngine.clearRuleFromCache(ruleId)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAbacRuleSchema,
-// implementedInApiVersion,
-// nameOf(getAbacRuleSchema),
-// "GET",
-// "/management/abac-rules-schema",
-// "Get ABAC Rule Schema",
-// s"""Get schema information about ABAC rule structure for building rule code.
-// |
-// |This endpoint returns schema information including:
-// |- All 18 parameters available in ABAC rules
-// |- Object types (User, Bank, Account, etc.) and their properties
-// |- Available operators and syntax
-// |- Example rules
-// |
-// |This schema information is useful for:
-// |- Building rule editors with auto-completion
-// |- Validating rule syntax in frontends
-// |- AI agents that help construct rules
-// |- Dynamic form builders
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// AbacRuleSchemaJsonV600(
-// parameters = List(
-// AbacParameterJsonV600(
-// name = "authenticatedUser",
-// `type` = "User",
-// description = "The logged-in user (always present)",
-// required = true,
-// category = "User"
-// )
-// ),
-// object_types = List(
-// AbacObjectTypeJsonV600(
-// name = "User",
-// description = "User object with profile information",
-// properties = List(
-// AbacObjectPropertyJsonV600(
-// name = "userId",
-// `type` = "String",
-// description = "Unique user ID"
-// )
-// )
-// )
-// ),
-// examples = List(
-// AbacRuleExampleJsonV600(
-// rule_name = "Check User Identity",
-// rule_code = "authenticatedUser.userId == user.userId",
-// description = "Verify that the authenticated user matches the target user",
-// policy = "user-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Check Specific Bank",
-// rule_code = "bankOpt.isDefined && bankOpt.get.bankId.value == \"gh.29.uk\"",
-// policy = "bank-access",
-// description = "Verify that the bank context is defined and matches a specific bank ID",
-// is_active = true
-// )
-// ),
-// available_operators = List("==", "!=", "&&", "||", "!", ">", "<", ">=", "<=", "contains", "isDefined"),
-// notes = List(
-// "Only authenticatedUser is guaranteed to exist (not wrapped in Option)",
-// "All other objects are Option types - use isDefined or pattern matching",
-// "Attributes are Lists - use .find(), .exists(), .forall() etc."
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canGetAbacRule))
-// )
-//
-// lazy val getAbacRuleSchema: OBPEndpoint = {
-// case "management" :: "abac-rules-schema" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetAbacRule, callContext)
-// } yield {
-// val metadata = AbacRuleSchemaJsonV600(
-// parameters = List(
-// AbacParameterJsonV600("authenticatedUser", "User", "The logged-in user (always present)", required = true, "User"),
-// AbacParameterJsonV600("authenticatedUserAttributes", "List[UserAttributeTrait]", "Non-personal attributes of authenticated user", required = true, "User"),
-// AbacParameterJsonV600("authenticatedUserAuthContext", "List[UserAuthContext]", "Auth context of authenticated user", required = true, "User"),
-// AbacParameterJsonV600("authenticatedUserEntitlements", "List[Entitlement]", "Entitlements (roles) of authenticated user", required = true, "User"),
-// AbacParameterJsonV600("onBehalfOfUserOpt", "Option[User]", "User being acted on behalf of (delegation)", required = false, "User"),
-// AbacParameterJsonV600("onBehalfOfUserAttributes", "List[UserAttributeTrait]", "Attributes of delegation user", required = false, "User"),
-// AbacParameterJsonV600("onBehalfOfUserAuthContext", "List[UserAuthContext]", "Auth context of delegation user", required = false, "User"),
-// AbacParameterJsonV600("onBehalfOfUserEntitlements", "List[Entitlement]", "Entitlements (roles) of delegation user", required = false, "User"),
-// AbacParameterJsonV600("userOpt", "Option[User]", "Target user being evaluated", required = false, "User"),
-// AbacParameterJsonV600("userAttributes", "List[UserAttributeTrait]", "Attributes of target user", required = false, "User"),
-// AbacParameterJsonV600("bankOpt", "Option[Bank]", "Bank context", required = false, "Bank"),
-// AbacParameterJsonV600("bankAttributes", "List[BankAttributeTrait]", "Bank attributes", required = false, "Bank"),
-// AbacParameterJsonV600("accountOpt", "Option[BankAccount]", "Account context", required = false, "Account"),
-// AbacParameterJsonV600("accountAttributes", "List[AccountAttribute]", "Account attributes", required = false, "Account"),
-// AbacParameterJsonV600("transactionOpt", "Option[Transaction]", "Transaction context", required = false, "Transaction"),
-// AbacParameterJsonV600("transactionAttributes", "List[TransactionAttribute]", "Transaction attributes", required = false, "Transaction"),
-// AbacParameterJsonV600("transactionRequestOpt", "Option[TransactionRequest]", "Transaction request context", required = false, "TransactionRequest"),
-// AbacParameterJsonV600("transactionRequestAttributes", "List[TransactionRequestAttributeTrait]", "Transaction request attributes", required = false, "TransactionRequest"),
-// AbacParameterJsonV600("customerOpt", "Option[Customer]", "Customer context", required = false, "Customer"),
-// AbacParameterJsonV600("customerAttributes", "List[CustomerAttribute]", "Customer attributes", required = false, "Customer"),
-// AbacParameterJsonV600("callContext", "Option[CallContext]", "Request call context with metadata (IP, user agent, etc.)", required = false, "Context")
-// ),
-// object_types = List(
-// AbacObjectTypeJsonV600("User", "User object with profile and authentication information", List(
-// AbacObjectPropertyJsonV600("userId", "String", "Unique user ID"),
-// AbacObjectPropertyJsonV600("emailAddress", "String", "User email address"),
-// AbacObjectPropertyJsonV600("provider", "String", "Authentication provider (e.g., 'obp')"),
-// AbacObjectPropertyJsonV600("name", "String", "User display name"),
-// AbacObjectPropertyJsonV600("idGivenByProvider", "String", "ID given by provider (same as username)"),
-// AbacObjectPropertyJsonV600("createdByConsentId", "Option[String]", "Consent ID that created the user (if any)"),
-// AbacObjectPropertyJsonV600("isDeleted", "Option[Boolean]", "Whether user is deleted")
-// )),
-// AbacObjectTypeJsonV600("Bank", "Bank object", List(
-// AbacObjectPropertyJsonV600("bankId", "BankId", "Bank ID"),
-// AbacObjectPropertyJsonV600("fullName", "String", "Bank full name"),
-// AbacObjectPropertyJsonV600("shortName", "String", "Bank short name"),
-// AbacObjectPropertyJsonV600("logoUrl", "String", "Bank logo URL"),
-// AbacObjectPropertyJsonV600("websiteUrl", "String", "Bank website URL"),
-// AbacObjectPropertyJsonV600("bankRoutingScheme", "String", "Bank routing scheme"),
-// AbacObjectPropertyJsonV600("bankRoutingAddress", "String", "Bank routing address")
-// )),
-// AbacObjectTypeJsonV600("BankAccount", "Bank account object", List(
-// AbacObjectPropertyJsonV600("accountId", "AccountId", "Account ID"),
-// AbacObjectPropertyJsonV600("bankId", "BankId", "Bank ID"),
-// AbacObjectPropertyJsonV600("accountType", "String", "Account type"),
-// AbacObjectPropertyJsonV600("balance", "BigDecimal", "Account balance"),
-// AbacObjectPropertyJsonV600("currency", "String", "Account currency"),
-// AbacObjectPropertyJsonV600("name", "String", "Account name"),
-// AbacObjectPropertyJsonV600("label", "String", "Account label"),
-// AbacObjectPropertyJsonV600("number", "String", "Account number"),
-// AbacObjectPropertyJsonV600("lastUpdate", "Date", "Last update date"),
-// AbacObjectPropertyJsonV600("branchId", "String", "Branch ID"),
-// AbacObjectPropertyJsonV600("accountRoutings", "List[AccountRouting]", "Account routings")
-// )),
-// AbacObjectTypeJsonV600("Transaction", "Transaction object", List(
-// AbacObjectPropertyJsonV600("id", "TransactionId", "Transaction ID"),
-// AbacObjectPropertyJsonV600("uuid", "String", "Universally unique ID"),
-// AbacObjectPropertyJsonV600("thisAccount", "BankAccount", "This account"),
-// AbacObjectPropertyJsonV600("otherAccount", "Counterparty", "Other account/counterparty"),
-// AbacObjectPropertyJsonV600("transactionType", "String", "Transaction type (e.g., cash withdrawal)"),
-// AbacObjectPropertyJsonV600("amount", "BigDecimal", "Transaction amount"),
-// AbacObjectPropertyJsonV600("currency", "String", "Transaction currency (ISO 4217)"),
-// AbacObjectPropertyJsonV600("description", "Option[String]", "Bank provided label"),
-// AbacObjectPropertyJsonV600("startDate", "Date", "Date transaction was initiated"),
-// AbacObjectPropertyJsonV600("finishDate", "Option[Date]", "Date money finished changing hands"),
-// AbacObjectPropertyJsonV600("balance", "BigDecimal", "New balance after transaction"),
-// AbacObjectPropertyJsonV600("status", "Option[String]", "Transaction status")
-// )),
-// AbacObjectTypeJsonV600("TransactionRequest", "Transaction request object", List(
-// AbacObjectPropertyJsonV600("id", "TransactionRequestId", "Transaction request ID"),
-// AbacObjectPropertyJsonV600("type", "String", "Transaction request type"),
-// AbacObjectPropertyJsonV600("from", "TransactionRequestAccount", "From account"),
-// AbacObjectPropertyJsonV600("status", "String", "Transaction request status"),
-// AbacObjectPropertyJsonV600("start_date", "Date", "Start date"),
-// AbacObjectPropertyJsonV600("end_date", "Date", "End date"),
-// AbacObjectPropertyJsonV600("transaction_ids", "String", "Associated transaction IDs"),
-// AbacObjectPropertyJsonV600("charge", "TransactionRequestCharge", "Charge information"),
-// AbacObjectPropertyJsonV600("this_bank_id", "BankId", "This bank ID"),
-// AbacObjectPropertyJsonV600("this_account_id", "AccountId", "This account ID"),
-// AbacObjectPropertyJsonV600("counterparty_id", "CounterpartyId", "Counterparty ID")
-// )),
-// AbacObjectTypeJsonV600("Customer", "Customer object", List(
-// AbacObjectPropertyJsonV600("customerId", "String", "Customer ID (UUID)"),
-// AbacObjectPropertyJsonV600("bankId", "String", "Bank ID"),
-// AbacObjectPropertyJsonV600("number", "String", "Customer number (bank identifier)"),
-// AbacObjectPropertyJsonV600("legalName", "String", "Customer legal name"),
-// AbacObjectPropertyJsonV600("mobileNumber", "String", "Customer mobile number"),
-// AbacObjectPropertyJsonV600("email", "String", "Customer email"),
-// AbacObjectPropertyJsonV600("dateOfBirth", "Date", "Date of birth"),
-// AbacObjectPropertyJsonV600("relationshipStatus", "String", "Relationship status"),
-// AbacObjectPropertyJsonV600("dependents", "Integer", "Number of dependents")
-// )),
-// AbacObjectTypeJsonV600("UserAttributeTrait", "User attribute", List(
-// AbacObjectPropertyJsonV600("name", "String", "Attribute name"),
-// AbacObjectPropertyJsonV600("value", "String", "Attribute value"),
-// AbacObjectPropertyJsonV600("attributeType", "AttributeType", "Attribute type (STRING, INTEGER, DOUBLE, DATE_WITH_DAY)")
-// )),
-// AbacObjectTypeJsonV600("AccountAttribute", "Account attribute", List(
-// AbacObjectPropertyJsonV600("name", "String", "Attribute name"),
-// AbacObjectPropertyJsonV600("value", "String", "Attribute value"),
-// AbacObjectPropertyJsonV600("attributeType", "AttributeType", "Attribute type")
-// )),
-// AbacObjectTypeJsonV600("TransactionAttribute", "Transaction attribute", List(
-// AbacObjectPropertyJsonV600("name", "String", "Attribute name"),
-// AbacObjectPropertyJsonV600("value", "String", "Attribute value"),
-// AbacObjectPropertyJsonV600("attributeType", "AttributeType", "Attribute type")
-// )),
-// AbacObjectTypeJsonV600("CustomerAttribute", "Customer attribute", List(
-// AbacObjectPropertyJsonV600("name", "String", "Attribute name"),
-// AbacObjectPropertyJsonV600("value", "String", "Attribute value"),
-// AbacObjectPropertyJsonV600("attributeType", "AttributeType", "Attribute type")
-// )),
-// AbacObjectTypeJsonV600("Entitlement", "User entitlement (role)", List(
-// AbacObjectPropertyJsonV600("entitlementId", "String", "Entitlement ID"),
-// AbacObjectPropertyJsonV600("roleName", "String", "Role name (e.g., CanCreateAccount, CanReadTransactions)"),
-// AbacObjectPropertyJsonV600("bankId", "String", "Bank ID (empty string for system-wide roles)"),
-// AbacObjectPropertyJsonV600("userId", "String", "User ID this entitlement belongs to")
-// )),
-// AbacObjectTypeJsonV600("CallContext", "Request context with metadata", List(
-// AbacObjectPropertyJsonV600("correlationId", "String", "Correlation ID for request tracking"),
-// AbacObjectPropertyJsonV600("url", "Option[String]", "Request URL"),
-// AbacObjectPropertyJsonV600("verb", "Option[String]", "HTTP verb (GET, POST, etc.)"),
-// AbacObjectPropertyJsonV600("ipAddress", "Option[String]", "Client IP address"),
-// AbacObjectPropertyJsonV600("userAgent", "Option[String]", "Client user agent"),
-// AbacObjectPropertyJsonV600("implementedByPartialFunction", "Option[String]", "Endpoint implementation name"),
-// AbacObjectPropertyJsonV600("startTime", "Option[Date]", "Request start time"),
-// AbacObjectPropertyJsonV600("endTime", "Option[Date]", "Request end time")
-// ))
-// ),
-// examples = List(
-// AbacRuleExampleJsonV600(
-// rule_name = "Branch Manager Internal Account Access",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanReadAccountsAtOneBank\") && authenticatedUserAttributes.exists(a => a.name == \"branch\" && accountAttributes.exists(aa => aa.name == \"branch\" && a.value == aa.value)) && callContext.exists(_.verb.exists(_ == \"GET\")) && accountOpt.exists(_.accountType == \"CURRENT\")",
-// description = "Allow GET access to current accounts when user has CanReadAccountsAtOneBank role and branch matches account's branch",
-// policy = "account-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Internal Network High-Value Transaction Review",
-// rule_code = "callContext.exists(_.ipAddress.exists(_.startsWith(\"10.\"))) && authenticatedUserEntitlements.exists(e => e.roleName == \"CanReadTransactionsAtOneBank\") && transactionOpt.exists(_.amount > 10000)",
-// description = "Allow users with CanReadTransactionsAtOneBank role on internal network to review high-value transactions over 10,000",
-// policy = "transaction-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Department Head Same-Department Account Read where overdrawn",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanReadAccountsAtOneBank\") && authenticatedUserAttributes.exists(ua => ua.name == \"department\" && accountAttributes.exists(aa => aa.name == \"department\" && ua.value == aa.value)) && callContext.exists(_.url.exists(_.contains(\"/accounts/\"))) && accountOpt.exists(_.balance < 0)",
-// description = "Allow users with CanReadAccountsAtOneBank role to read overdrawn accounts in their department",
-// policy = "account-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Manager Internal Network Transaction Approval",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanCreateTransactionRequest\") && callContext.exists(_.ipAddress.exists(ip => ip.startsWith(\"10.\") || ip.startsWith(\"192.168.\"))) && transactionRequestOpt.exists(tr => tr.status == \"PENDING\" && tr.charge.value.toDouble < 50000)",
-// description = "Allow users with CanCreateTransactionRequest role on internal network to approve pending transaction requests under 50,000",
-// policy = "transaction-request",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "KYC Officer Customer Creation from Branch",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanCreateCustomer\") && authenticatedUserAttributes.exists(a => a.name == \"certification\" && a.value == \"kyc_certified\") && callContext.exists(_.verb.exists(_ == \"POST\")) && callContext.exists(_.ipAddress.exists(_.startsWith(\"10.20.\"))) && customerAttributes.exists(ca => ca.name == \"onboarding_status\" && ca.value == \"pending\")",
-// description = "Allow users with CanCreateCustomer role and KYC certification to create customers via POST from branch network (10.20.x.x) when status is pending",
-// policy = "customer-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "International Team Foreign Currency Transaction",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanReadTransactionsAtOneBank\") && authenticatedUserAttributes.exists(a => a.name == \"team\" && a.value == \"international\") && callContext.exists(_.url.exists(_.contains(\"/transactions/\"))) && transactionOpt.exists(t => t.currency != \"USD\" && t.amount < 100000) && accountOpt.exists(a => accountAttributes.exists(aa => aa.name == \"international_enabled\" && aa.value == \"true\"))",
-// description = "Allow international team users with CanReadTransactionsAtOneBank role to access foreign currency transactions under 100k on international-enabled accounts",
-// policy = "transaction-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Assistant with Limited Delegation Account View",
-// rule_code = "onBehalfOfUserOpt.isDefined && onBehalfOfUserEntitlements.exists(e => e.roleName == \"CanReadAccountsAtOneBank\") && authenticatedUserAttributes.exists(a => a.name == \"assistant_of\" && onBehalfOfUserOpt.exists(u => a.value == u.userId)) && callContext.exists(_.verb.exists(_ == \"GET\")) && accountOpt.exists(a => accountAttributes.exists(aa => aa.name == \"tier\" && List(\"gold\", \"platinum\").contains(aa.value)))",
-// description = "Allow assistants to view gold/platinum accounts via GET when acting on behalf of a user with CanReadAccountsAtOneBank role",
-// policy = "account-access",
-// is_active = true
-// ),
-// AbacRuleExampleJsonV600(
-// rule_name = "Fraud Analyst High-Risk Transaction Access",
-// rule_code = "authenticatedUserEntitlements.exists(e => e.roleName == \"CanReadTransactionsAtOneBank\") && callContext.exists(c => c.verb.exists(_ == \"GET\") && c.implementedByPartialFunction.exists(_.contains(\"Transaction\"))) && transactionAttributes.exists(ta => ta.name == \"risk_score\" && ta.value.toInt >= 75) && transactionOpt.exists(_.status.exists(_ != \"COMPLETED\"))",
-// description = "Allow users with CanReadTransactionsAtOneBank role to GET high-risk (score ≥75) non-completed transactions",
-// policy = "transaction-access",
-// is_active = true
-// )
-// ),
-// available_operators = List(
-// "==", "!=", "&&", "||", "!", ">", "<", ">=", "<=",
-// "contains", "startsWith", "endsWith",
-// "isDefined", "isEmpty", "nonEmpty",
-// "exists", "forall", "find", "filter",
-// "get", "getOrElse"
-// ),
-// notes = List(
-// "PARAMETER NAMES: Use authenticatedUser, userOpt, accountOpt, bankOpt, transactionOpt, etc. (NOT user, account, bank)",
-// "PROPERTY NAMES: Use camelCase - userId (NOT user_id), accountId (NOT account_id), emailAddress (NOT email_address)",
-// "OPTION TYPES: Only authenticatedUser is guaranteed to exist. All others are Option types - check isDefined before using .get",
-// "ATTRIBUTES: All attributes are Lists - use Scala collection methods like exists(), find(), filter()",
-// "SAFE OPTION HANDLING: Use pattern matching: userOpt match { case Some(u) => u.userId == ... case None => false }",
-// "RETURN TYPE: Rule must return Boolean - true = access granted, false = access denied",
-// "AUTO-FETCHING: Objects are automatically fetched based on IDs passed to execute endpoint",
-// "COMMON MISTAKE: Writing 'user.user_id' instead of 'userOpt.get.userId' or 'authenticatedUser.userId'"
-// )
-// )
-// (metadata, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAbacPolicies,
-// implementedInApiVersion,
-// nameOf(getAbacPolicies),
-// "GET",
-// "/management/abac-policies",
-// "Get ABAC Policies",
-// s"""Get the list of allowed ABAC policy names.
-// |
-// |ABAC rules are organized by policies. Each rule must have at least one policy assigned.
-// |Rules can have multiple policies (comma-separated). This endpoint returns the list of
-// |standardized policy names that should be used when creating or updating rules.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// AbacPoliciesJsonV600(
-// policies = List(
-// AbacPolicyJsonV600(
-// policy = "account-access",
-// description = "Rules for controlling access to account information"
-// )
-// )
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canGetAbacRule))
-// )
-//
-// lazy val getAbacPolicies: OBPEndpoint = {
-// case "management" :: "abac-policies" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canGetAbacRule, callContext)
-// } yield {
-// val policies = Constant.ABAC_POLICIES.map { policy =>
-// AbacPolicyJsonV600(
-// policy = policy,
-// description = Constant.ABAC_POLICY_DESCRIPTIONS.getOrElse(policy, "No description available")
-// )
-// }
-//
-// (AbacPoliciesJsonV600(policies), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// validateAbacRule,
-// implementedInApiVersion,
-// nameOf(validateAbacRule),
-// "POST",
-// "/management/abac-rules/validate",
-// "Validate ABAC Rule",
-// s"""Validate ABAC rule code syntax and structure without creating or executing the rule.
-// |
-// |This endpoint performs the following validations:
-// |- Parse the rule_code as a Scala expression
-// |- Validate syntax - check for parsing errors
-// |- Validate field references - check if referenced objects/fields exist
-// |- Check type consistency - verify the expression returns a Boolean
-// |
-// |**Available ABAC Context Objects:**
-// |- AuthenticatedUser - The user who is logged in
-// |- OnBehalfOfUser - Optional delegation user
-// |- User - Target user being evaluated
-// |- Bank, Account, View, Transaction, TransactionRequest, Customer
-// |- Attributes for each entity (e.g., userAttributes, accountAttributes)
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |
-// |This is a "dry-run" validation that does NOT save or execute the rule.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// ValidateAbacRuleJsonV600(
-// rule_code = """AuthenticatedUser.user_id == Account.owner_id"""
-// ),
-// ValidateAbacRuleSuccessJsonV600(
-// valid = true,
-// message = "ABAC rule code is valid"
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canCreateAbacRule))
-// )
-//
-// lazy val validateAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: "validate" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canCreateAbacRule, callContext)
-// validateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) {
-// json.extract[ValidateAbacRuleJsonV600]
-// }
-// _ <- NewStyle.function.tryons(s"$AbacRuleCodeEmpty", 400, callContext) {
-// validateJson.rule_code.trim.nonEmpty
-// }
-// validationResult <- AbacRuleEngine.validateRuleCodeAsync(validateJson.rule_code).map {
-// case Full(msg) =>
-// Full(ValidateAbacRuleSuccessJsonV600(
-// valid = true,
-// message = msg
-// ))
-// case Failure(errorMsg, _, _) =>
-// // Extract error details from the error message
-// val cleanError = errorMsg.replace("Invalid ABAC rule code: ", "").replace("Failed to compile ABAC rule: ", "")
-//
-// // Determine the proper OBP error message and error type
-// val (obpErrorMessage, errorType) = if (cleanError.toLowerCase.contains("too permissive") || cleanError.toLowerCase.contains("tautological")) {
-// val errorConst = if (cleanError.toLowerCase.contains("statistical")) AbacRuleStatisticallyTooPermissive else AbacRuleTooPermissive
-// (errorConst, "PermissivenessError")
-// } else if (cleanError.toLowerCase.contains("type mismatch") || cleanError.toLowerCase.contains("found:") && cleanError.toLowerCase.contains("required: boolean")) {
-// (AbacRuleTypeMismatch, "TypeError")
-// } else if (cleanError.toLowerCase.contains("syntax") || cleanError.toLowerCase.contains("parse")) {
-// (AbacRuleSyntaxError, "SyntaxError")
-// } else if (cleanError.toLowerCase.contains("not found") || cleanError.toLowerCase.contains("not a member")) {
-// (AbacRuleFieldReferenceError, "FieldReferenceError")
-// } else if (cleanError.toLowerCase.contains("compilation failed") || cleanError.toLowerCase.contains("reflective compilation has failed")) {
-// (AbacRuleCompilationFailed, "CompilationError")
-// } else {
-// (AbacRuleValidationFailed, "ValidationError")
-// }
-//
-// Full(ValidateAbacRuleFailureJsonV600(
-// valid = false,
-// error = cleanError,
-// message = obpErrorMessage,
-// details = ValidateAbacRuleErrorDetailsJsonV600(
-// error_type = errorType
-// )
-// ))
-// case Empty =>
-// Full(ValidateAbacRuleFailureJsonV600(
-// valid = false,
-// error = "Unknown validation error",
-// message = AbacRuleValidationFailed,
-// details = ValidateAbacRuleErrorDetailsJsonV600(
-// error_type = "UnknownError"
-// )
-// ))
-// } map {
-// unboxFullOrFail(_, callContext, AbacRuleValidationFailed, 400)
-// }
-// } yield {
-// (validationResult, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// validateDynamicResourceDoc,
-// implementedInApiVersion,
-// nameOf(validateDynamicResourceDoc),
-// "POST",
-// "/management/dynamic-resource-docs/validate",
-// "Validate Dynamic Resource Doc",
-// s"""Dry-run validation of a Dynamic Resource Doc. Send the same payload you would send to `Create Dynamic Resource Doc` and this endpoint will:
-// |
-// |- Parse `method_body` (URL-decoded) as Scala code and run the ToolBox compiler against it, wrapped in the same template used at runtime (request/response case classes generated from `example_request_body` / `success_response_body`).
-// |- Run the OBP compilation-dependency guard (when the OBP prop `dynamic_code_compile_validate_enable` is set to `true`).
-// |
-// |Always returns HTTP 200. Inspect the `valid` field in the response:
-// |
-// |* `true` — the Scala compiles and all referenced OBP methods are on the allowlist.
-// |* `false` — the response includes `error` (raw compiler / guard message), `message` (OBP error constant) and `details.error_type` — one of:
-// | * `CompilationError` — `method_body` failed to compile.
-// | * `DependencyError` — compiled, but references OBP types/methods that the admin has not allowed in `dynamic_code_compile_validate_dependencies`.
-// | * `UnknownError` — any other unexpected exception.
-// |
-// |Nothing is persisted and no endpoint is served as a result of calling this.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None),
-// ValidateDynamicResourceDocSuccessJsonV600(
-// valid = true,
-// message = "Dynamic Resource Doc method body is valid Scala and uses allowed dependencies."
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagDynamicResourceDoc),
-// Some(List(canCreateDynamicResourceDoc))
-// )
-//
-// lazy val validateDynamicResourceDoc: OBPEndpoint = {
-// case "management" :: "dynamic-resource-docs" :: "validate" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canCreateDynamicResourceDoc, callContext)
-// body <- NewStyle.function.tryons(
-// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc",
-// 400,
-// callContext
-// ) {
-// json.extract[JsonDynamicResourceDoc]
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""",
-// cc = callContext
-// ) {
-// Set("POST", "PUT", "GET", "DELETE").contains(body.requestVerb)
-// }
-// _ <- Helper.booleanToFuture(
-// failMsg = s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""",
-// cc = callContext
-// ) {
-// (body.requestVerb, body.exampleRequestBody) match {
-// case ("GET" | "DELETE", Some(JString(s))) => StringUtils.isBlank(s)
-// case ("GET" | "DELETE", Some(rb)) => rb == JNothing
-// case _ => true
-// }
-// }
-// result = try {
-// CompiledObjects(body.exampleRequestBody, body.successResponseBody, body.methodBody)
-// .validateDependency()
-// ValidateDynamicResourceDocSuccessJsonV600(
-// valid = true,
-// message = "Dynamic Resource Doc method body is valid Scala and uses allowed dependencies."
-// )
-// } catch {
-// case e: JsonResponseException =>
-// // validateDependency throws JsonResponseException (OBP-40046) when the compiled
-// // code references types/methods outside the compile-time allowlist. The useful
-// // error text is in the response body, not getMessage.
-// val errorText = e.jsonResponse match {
-// case JsonResponseExtractor(msg, _) => msg
-// case _ => ""
-// }
-// ValidateDynamicResourceDocFailureJsonV600(
-// valid = false,
-// error = errorText,
-// message = DynamicResourceDocMethodDependency,
-// details = ValidateDynamicResourceDocErrorDetailsJsonV600(error_type = "DependencyError")
-// )
-// case e: Exception =>
-// ValidateDynamicResourceDocFailureJsonV600(
-// valid = false,
-// error = Option(e.getMessage).getOrElse(""),
-// message = DynamicCodeCompileFail,
-// details = ValidateDynamicResourceDocErrorDetailsJsonV600(error_type = "CompilationError")
-// )
-// }
-// } yield {
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// executeAbacRule,
-// implementedInApiVersion,
-// nameOf(executeAbacRule),
-// "POST",
-// "/management/abac-rules/ABAC_RULE_ID/execute",
-// "Execute ABAC Rule",
-// s"""Execute an ABAC rule to test access control.
-// |
-// |This endpoint allows you to test an ABAC rule with specific context (authenticated user, bank, account, transaction, customer, etc.).
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |- ${Glossary.getGlossaryItemLink("ABAC_Testing_Examples")} - Testing examples and patterns
-// |
-// |You can provide optional IDs in the request body to test the rule with specific context.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// ExecuteAbacRuleJsonV600(
-// authenticated_user_id = Some("c7b6cb47-cb96-4441-8801-35b57456753a"),
-// on_behalf_of_user_id = Some("a3b5c123-1234-5678-9012-fedcba987654"),
-// user_id = Some("c7b6cb47-cb96-4441-8801-35b57456753a"),
-// bank_id = Some("gh.29.uk"),
-// account_id = Some("8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0"),
-// view_id = Some("owner"),
-// transaction_request_id = Some("123456"),
-// transaction_id = Some("abc123"),
-// customer_id = Some("customer-id-123")
-// ),
-// AbacRuleResultJsonV600(
-// result = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canExecuteAbacRule))
-// )
-//
-// lazy val executeAbacRule: OBPEndpoint = {
-// case "management" :: "abac-rules" :: ruleId :: "execute" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canExecuteAbacRule, callContext)
-// execJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) {
-// json.extract[ExecuteAbacRuleJsonV600]
-// }
-// rule <- Future {
-// MappedAbacRuleProvider.getAbacRuleById(ruleId)
-// } map {
-// unboxFullOrFail(_, callContext, s"ABAC Rule not found with ID: $ruleId", 404)
-// }
-//
-// // Execute the rule with IDs - object fetching happens internally
-// // authenticatedUserId: can be provided in request (for testing) or defaults to actual authenticated user
-// // onBehalfOfUserId: optional delegation - acting on behalf of another user
-// // userId: the target user being evaluated (defaults to authenticated user)
-// effectiveAuthenticatedUserId = execJson.authenticated_user_id.getOrElse(user.userId)
-//
-// result <- AbacRuleEngine.executeRule(
-// ruleId = ruleId,
-// authenticatedUserId = effectiveAuthenticatedUserId,
-// onBehalfOfUserId = execJson.on_behalf_of_user_id,
-// userId = execJson.user_id,
-// callContext = callContext.getOrElse(cc),
-// bankId = execJson.bank_id,
-// accountId = execJson.account_id,
-// viewId = execJson.view_id,
-// transactionId = execJson.transaction_id,
-// transactionRequestId = execJson.transaction_request_id,
-// customerId = execJson.customer_id
-// ).map {
-// case Full(allowed) =>
-// AbacRuleResultJsonV600(result = allowed)
-// case Failure(msg, _, _) =>
-// AbacRuleResultJsonV600(result = false)
-// case Empty =>
-// AbacRuleResultJsonV600(result = false)
-// }
-// } yield {
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// executeAbacPolicy,
-// implementedInApiVersion,
-// nameOf(executeAbacPolicy),
-// "POST",
-// "/management/abac-policies/POLICY/execute",
-// "Execute ABAC Policy",
-// s"""Execute all ABAC rules in a policy to test access control.
-// |
-// |This endpoint executes all active rules that belong to the specified policy.
-// |The policy uses OR logic - access is granted if at least one rule passes.
-// |
-// |This allows you to test a complete policy with specific context (authenticated user, bank, account, transaction, customer, etc.).
-// |
-// |**Documentation:**
-// |- ${Glossary.getGlossaryItemLink("ABAC_Simple_Guide")} - Getting started with ABAC rules
-// |- ${Glossary.getGlossaryItemLink("ABAC_Parameters_Summary")} - Complete list of all 18 parameters
-// |- ${Glossary.getGlossaryItemLink("ABAC_Object_Properties_Reference")} - Detailed property reference
-// |- ${Glossary.getGlossaryItemLink("ABAC_Testing_Examples")} - Testing examples and patterns
-// |
-// |You can provide optional IDs in the request body to test the policy with specific context.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// ExecuteAbacRuleJsonV600(
-// authenticated_user_id = Some("c7b6cb47-cb96-4441-8801-35b57456753a"),
-// on_behalf_of_user_id = Some("a3b5c123-1234-5678-9012-fedcba987654"),
-// user_id = Some("c7b6cb47-cb96-4441-8801-35b57456753a"),
-// bank_id = Some("gh.29.uk"),
-// account_id = Some("8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0"),
-// view_id = Some("owner"),
-// transaction_request_id = Some("123456"),
-// transaction_id = Some("abc123"),
-// customer_id = Some("customer-id-123")
-// ),
-// AbacRuleResultJsonV600(
-// result = true
-// ),
-// List(
-// AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagABAC),
-// Some(List(canExecuteAbacRule))
-// )
-//
-// lazy val executeAbacPolicy: OBPEndpoint = {
-// case "management" :: "abac-policies" :: policy :: "execute" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(user), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", user.userId, canExecuteAbacRule, callContext)
-// execJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) {
-// json.extract[ExecuteAbacRuleJsonV600]
-// }
-//
-// // Verify the policy exists
-// _ <- Future {
-// if (Constant.ABAC_POLICIES.contains(policy)) {
-// Full(true)
-// } else {
-// Failure(s"Policy not found: $policy. Available policies: ${Constant.ABAC_POLICIES.mkString(", ")}")
-// }
-// } map {
-// unboxFullOrFail(_, callContext, s"Invalid ABAC Policy: $policy", 404)
-// }
-//
-// // Execute the policy with IDs - object fetching happens internally
-// // authenticatedUserId: can be provided in request (for testing) or defaults to actual authenticated user
-// // onBehalfOfUserId: optional delegation - acting on behalf of another user
-// // userId: the target user being evaluated (defaults to authenticated user)
-// effectiveAuthenticatedUserId = execJson.authenticated_user_id.getOrElse(user.userId)
-//
-// result <- AbacRuleEngine.executeRulesByPolicy(
-// policy = policy,
-// authenticatedUserId = effectiveAuthenticatedUserId,
-// onBehalfOfUserId = execJson.on_behalf_of_user_id,
-// userId = execJson.user_id,
-// callContext = callContext.getOrElse(cc),
-// bankId = execJson.bank_id,
-// accountId = execJson.account_id,
-// viewId = execJson.view_id,
-// transactionId = execJson.transaction_id,
-// transactionRequestId = execJson.transaction_request_id,
-// customerId = execJson.customer_id
-// ).map {
-// case Full(allowed) =>
-// AbacRuleResultJsonV600(result = allowed)
-// case Failure(msg, _, _) =>
-// AbacRuleResultJsonV600(result = false)
-// case Empty =>
-// AbacRuleResultJsonV600(result = false)
-// }
-// } yield {
-// (result, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ============================================================================================================
-// // USER ATTRIBUTES v6.0.0 - Consistent with other entity attributes
-// // ============================================================================================================
-// // "user attributes" = IsPersonal=false (requires roles) - consistent with other entity attributes
-// // "personal user attributes" = IsPersonal=true (no roles, user manages their own)
-// // ============================================================================================================
-//
-// staticResourceDocs += ResourceDoc(
-// createUserAttribute,
-// implementedInApiVersion,
-// nameOf(createUserAttribute),
-// "POST",
-// "/users/USER_ID/attributes",
-// "Create User Attribute",
-// s"""Create a User Attribute for the user specified by USER_ID.
-// |
-// |User Attributes are non-personal attributes (IsPersonal=false) that can be used in ABAC rules.
-// |They require a role to set, similar to Customer Attributes, Account Attributes, etc.
-// |
-// |For personal attributes that users manage themselves, see the /my/personal-data-fields endpoints.
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or "DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// code.api.v5_1_0.UserAttributeJsonV510(
-// name = "account_type",
-// `type` = "STRING",
-// value = "premium"
-// ),
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List(canCreateUserAttribute))
-// )
-//
-// lazy val createUserAttribute: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateUserAttribute, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the UserAttributeJsonV510"
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[code.api.v5_1_0.UserAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `type` field can only accept: ${UserAttributeType.DOUBLE}, ${UserAttributeType.STRING}, ${UserAttributeType.INTEGER}, ${UserAttributeType.DATE_WITH_DAY}"
-// userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
-// user.userId,
-// None,
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// false, // IsPersonal = false for user attributes
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserAttributes,
-// implementedInApiVersion,
-// nameOf(getUserAttributes),
-// "GET",
-// "/users/USER_ID/attributes",
-// "Get User Attributes",
-// s"""Get User Attributes for the user specified by USER_ID.
-// |
-// |Returns non-personal user attributes (IsPersonal=false) that can be used in ABAC rules.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// code.api.v5_1_0.UserAttributesResponseJsonV510(
-// user_attributes = List(userAttributeResponseJsonV510)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List(canGetUserAttributes))
-// )
-//
-// lazy val getUserAttributes: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetUserAttributes, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// (attributes, callContext) <- NewStyle.function.getNonPersonalUserAttributes(user.userId, callContext)
-// } yield {
-// (code.api.v5_1_0.UserAttributesResponseJsonV510(attributes.map(JSONFactory510.createUserAttributeJson)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUserAttributeById,
-// implementedInApiVersion,
-// nameOf(getUserAttributeById),
-// "GET",
-// "/users/USER_ID/attributes/USER_ATTRIBUTE_ID",
-// "Get User Attribute By Id",
-// s"""Get a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// UserAttributeNotFound,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List(canGetUserAttributes))
-// )
-//
-// lazy val getUserAttributeById: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: userAttributeId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canGetUserAttributes, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// (attributes, callContext) <- NewStyle.function.getNonPersonalUserAttributes(user.userId, callContext)
-// attribute <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// } yield {
-// (JSONFactory510.createUserAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateUserAttribute,
-// implementedInApiVersion,
-// nameOf(updateUserAttribute),
-// "PUT",
-// "/users/USER_ID/attributes/USER_ATTRIBUTE_ID",
-// "Update User Attribute",
-// s"""Update a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// code.api.v5_1_0.UserAttributeJsonV510(
-// name = "account_type",
-// `type` = "STRING",
-// value = "enterprise"
-// ),
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// UserAttributeNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List(canUpdateUserAttribute))
-// )
-//
-// lazy val updateUserAttribute: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: userAttributeId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateUserAttribute, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// failMsg = s"$InvalidJsonFormat The Json body should be the UserAttributeJsonV510"
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[code.api.v5_1_0.UserAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `type` field can only accept: ${UserAttributeType.DOUBLE}, ${UserAttributeType.STRING}, ${UserAttributeType.INTEGER}, ${UserAttributeType.DATE_WITH_DAY}"
-// userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (attributes, callContext) <- NewStyle.function.getNonPersonalUserAttributes(user.userId, callContext)
-// _ <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
-// user.userId,
-// Some(userAttributeId),
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// false, // IsPersonal = false for user attributes
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteUserAttribute,
-// implementedInApiVersion,
-// nameOf(deleteUserAttribute),
-// "DELETE",
-// "/users/USER_ID/attributes/USER_ATTRIBUTE_ID",
-// "Delete User Attribute",
-// s"""Delete a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UserNotFoundByUserId,
-// UserAttributeNotFound,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List(canDeleteUserAttribute))
-// )
-//
-// lazy val deleteUserAttribute: OBPEndpoint = {
-// case "users" :: userId :: "attributes" :: userAttributeId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteUserAttribute, callContext)
-// (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
-// (attributes, callContext) <- NewStyle.function.getNonPersonalUserAttributes(user.userId, callContext)
-// _ <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// (deleted, callContext) <- Connector.connector.vend.deleteUserAttribute(
-// userAttributeId,
-// callContext
-// ) map {
-// i => (connectorEmptyResponse(i._1, callContext), i._2)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // ============================================================================================================
-// // PERSONAL DATA FIELDS - User manages their own personal data fields
-// // ============================================================================================================
-//
-// staticResourceDocs += ResourceDoc(
-// createPersonalDataField,
-// implementedInApiVersion,
-// nameOf(createPersonalDataField),
-// "POST",
-// "/my/personal-data-fields",
-// "Create Personal Data Field",
-// s"""Create a Personal Data Field for the currently authenticated user.
-// |
-// |Personal Data Fields (IsPersonal=true) are managed by the user themselves and do not require special roles.
-// |This data is not available in ABAC rules for privacy reasons.
-// |
-// |For non-personal attributes that can be used in ABAC rules, see the /users/USER_ID/attributes endpoints.
-// |
-// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or "DATE_WITH_DAY"
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// code.api.v5_1_0.UserAttributeJsonV510(
-// name = "favorite_color",
-// `type` = "STRING",
-// value = "blue"
-// ),
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List())
-// )
-//
-// lazy val createPersonalDataField: OBPEndpoint = {
-// case "my" :: "personal-data-fields" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// failMsg = s"$InvalidJsonFormat The Json body should be the UserAttributeJsonV510"
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[code.api.v5_1_0.UserAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `type` field can only accept: ${UserAttributeType.DOUBLE}, ${UserAttributeType.STRING}, ${UserAttributeType.INTEGER}, ${UserAttributeType.DATE_WITH_DAY}"
-// userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
-// u.userId,
-// None,
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// true, // IsPersonal = true for personal user attributes
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPersonalDataFields,
-// implementedInApiVersion,
-// nameOf(getPersonalDataFields),
-// "GET",
-// "/my/personal-data-fields",
-// "Get Personal Data Fields",
-// s"""Get Personal Data Fields for the currently authenticated user.
-// |
-// |Returns Personal Data Fields (IsPersonal=true) that are managed by the user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// code.api.v5_1_0.UserAttributesResponseJsonV510(
-// user_attributes = List(userAttributeResponseJsonV510)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List())
-// )
-//
-// lazy val getPersonalDataFields: OBPEndpoint = {
-// case "my" :: "personal-data-fields" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(u.userId, callContext)
-// } yield {
-// (code.api.v5_1_0.UserAttributesResponseJsonV510(attributes.map(JSONFactory510.createUserAttributeJson)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPersonalDataFieldById,
-// implementedInApiVersion,
-// nameOf(getPersonalDataFieldById),
-// "GET",
-// "/my/personal-data-fields/USER_ATTRIBUTE_ID",
-// "Get Personal Data Field By Id",
-// s"""Get a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserAttributeNotFound,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List())
-// )
-//
-// lazy val getPersonalDataFieldById: OBPEndpoint = {
-// case "my" :: "personal-data-fields" :: userAttributeId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(u.userId, callContext)
-// attribute <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// } yield {
-// (JSONFactory510.createUserAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updatePersonalDataField,
-// implementedInApiVersion,
-// nameOf(updatePersonalDataField),
-// "PUT",
-// "/my/personal-data-fields/USER_ATTRIBUTE_ID",
-// "Update Personal Data Field",
-// s"""Update a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// code.api.v5_1_0.UserAttributeJsonV510(
-// name = "favorite_color",
-// `type` = "STRING",
-// value = "green"
-// ),
-// userAttributeResponseJsonV510,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserAttributeNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List())
-// )
-//
-// lazy val updatePersonalDataField: OBPEndpoint = {
-// case "my" :: "personal-data-fields" :: userAttributeId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// failMsg = s"$InvalidJsonFormat The Json body should be the UserAttributeJsonV510"
-// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// json.extract[code.api.v5_1_0.UserAttributeJsonV510]
-// }
-// failMsg = s"$InvalidJsonFormat The `type` field can only accept: ${UserAttributeType.DOUBLE}, ${UserAttributeType.STRING}, ${UserAttributeType.INTEGER}, ${UserAttributeType.DATE_WITH_DAY}"
-// userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
-// UserAttributeType.withName(postedData.`type`)
-// }
-// (attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(u.userId, callContext)
-// _ <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
-// u.userId,
-// Some(userAttributeId),
-// postedData.name,
-// userAttributeType,
-// postedData.value,
-// true, // IsPersonal = true for personal user attributes
-// callContext
-// )
-// } yield {
-// (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deletePersonalDataField,
-// implementedInApiVersion,
-// nameOf(deletePersonalDataField),
-// "DELETE",
-// "/my/personal-data-fields/USER_ATTRIBUTE_ID",
-// "Delete Personal Data Field",
-// s"""Delete a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.
-// |
-// |${userAuthenticationMessage(true)}
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserAttributeNotFound,
-// UnknownError
-// ),
-// List(apiTagUser, apiTagUserAttribute, apiTagAttribute),
-// Some(List())
-// )
-//
-// lazy val deletePersonalDataField: OBPEndpoint = {
-// case "my" :: "personal-data-fields" :: userAttributeId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(u.userId, callContext)
-// _ <- Future {
-// attributes.find(_.userAttributeId == userAttributeId)
-// } map {
-// unboxFullOrFail(_, callContext, UserAttributeNotFound, 404)
-// }
-// (deleted, callContext) <- Connector.connector.vend.deleteUserAttribute(
-// userAttributeId,
-// callContext
-// ) map {
-// i => (connectorEmptyResponse(i._1, callContext), i._2)
-// }
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMessageDocsJsonSchema,
-// implementedInApiVersion,
-// nameOf(getMessageDocsJsonSchema),
-// "GET",
-// "/message-docs/CONNECTOR/json-schema",
-// "Get Message Docs as JSON Schema",
-// """Returns message documentation as JSON Schema format for code generation in any language.
-// |
-// |This endpoint provides machine-readable schemas instead of just examples, making it ideal for:
-// |- AI-powered code generation
-// |- Automatic adapter creation in multiple languages
-// |- Type-safe client generation with tools like quicktype
-// |
-// |**Supported Connectors:**
-// |- rabbitmq_vOct2024 - RabbitMQ connector message schemas
-// |- rest_vMar2019 - REST connector message schemas
-// |- akka_vDec2018 - Akka connector message schemas
-// |- kafka_vMay2019 - Kafka connector message schemas (if available)
-// |
-// |**Code Generation Examples:**
-// |
-// |Generate Scala code with Circe:
-// |```bash
-// |curl https://api.../message-docs/rabbitmq_vOct2024/json-schema > schemas.json
-// |quicktype -s schema schemas.json -o Messages.scala --framework circe
-// |```
-// |
-// |Generate Python code:
-// |```bash
-// |quicktype -s schema schemas.json -o messages.py --lang python
-// |```
-// |
-// |Generate TypeScript code:
-// |```bash
-// |quicktype -s schema schemas.json -o messages.ts --lang typescript
-// |```
-// |
-// |**Schema Structure:**
-// |Each message includes:
-// |- `process` - The connector method name (e.g., "obp.getAdapterInfo")
-// |- `description` - Human-readable description of what the message does
-// |- `outbound_schema` - JSON Schema for request messages (OBP-API -> Adapter)
-// |- `inbound_schema` - JSON Schema for response messages (Adapter -> OBP-API)
-// |
-// |All nested type definitions are included in the `definitions` section for reuse.
-// |
-// |**Authentication:**
-// |This endpoint is publicly accessible (no authentication required) to facilitate adapter development.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// InvalidConnector,
-// UnknownError
-// ),
-// List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)
-// )
-//
-// lazy val getMessageDocsJsonSchema: OBPEndpoint = {
-// case "message-docs" :: connector :: "json-schema" :: Nil JsonGet _ => {
-// cc => {
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// cacheKey = s"message-docs-json-schema-$connector"
-// cacheValueFromRedis = Caching.getStaticSwaggerDocCache(cacheKey)
-// jsonSchema <- if (cacheValueFromRedis.isDefined) {
-// NewStyle.function.tryons(s"$UnknownError Cannot parse cached JSON Schema.", 400, callContext) {
-// json.parse(cacheValueFromRedis.get).asInstanceOf[JObject]
-// }
-// } else {
-// NewStyle.function.tryons(s"$UnknownError Cannot generate JSON Schema.", 400, callContext) {
-// val connectorObjectBox = tryo{Connector.getConnectorInstance(connector)}
-// val connectorObject = unboxFullOrFail(
-// connectorObjectBox,
-// callContext,
-// s"$InvalidConnector Current input is: $connector. Valid connectors include: rabbitmq_vOct2024, rest_vMar2019, akka_vDec2018"
-// )
-// val schema = JsonSchemaGenerator.messageDocsToJsonSchema(
-// connectorObject.messageDocs.toList,
-// connector
-// )
-// val schemaString = json.compactRender(schema)
-// Caching.setStaticSwaggerDocCache(cacheKey, schemaString)
-// schema
-// }
-// }
-// } yield {
-// (jsonSchema, HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getMyDynamicEntities),
-// "GET",
-// "/my/dynamic-entities",
-// "Get My Dynamic Entities",
-// s"""Get all Dynamic Entity definitions I created.
-// |
-// |This v6.0.0 endpoint returns a cleaner response format with:
-// |* snake_case field names (dynamic_entity_id, user_id, bank_id, has_personal_entity)
-// |* An explicit entity_name field instead of using the entity name as a dynamic JSON key
-// |* The entity schema in a separate definition object
-// |
-// |For more information see ${Glossary.getGlossaryItemLink(
-// "My-Dynamic-Entities"
-// )}""",
-// EmptyBody,
-// MyDynamicEntitiesJsonV600(
-// dynamic_entities = List(
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[org.json4s.JsonAST.JObject],
-// _links = Some(DynamicEntityLinksJsonV600(
-// related = List(
-// RelatedLinkJsonV600("personal-list", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences", "GET"),
-// RelatedLinkJsonV600("personal-create", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences", "POST"),
-// RelatedLinkJsonV600("personal-read", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"),
-// RelatedLinkJsonV600("personal-update", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"),
-// RelatedLinkJsonV600("personal-delete", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE")
-// )
-// ))
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi)
-// )
-//
-// lazy val getMyDynamicEntities: OBPEndpoint = {
-// case "my" :: "dynamic-entities" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// dynamicEntities <- Future(
-// NewStyle.function.getDynamicEntitiesByUserId(cc.userId)
-// )
-// } yield {
-// val listCommons: List[DynamicEntityCommons] = dynamicEntities
-// (
-// JSONFactory600.createMyDynamicEntitiesJson(listCommons),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAvailablePersonalDynamicEntities,
-// implementedInApiVersion,
-// nameOf(getAvailablePersonalDynamicEntities),
-// "GET",
-// "/personal-dynamic-entities/available",
-// "Get Available Personal Dynamic Entities",
-// s"""Get all Dynamic Entities that support personal data storage (hasPersonalEntity == true).
-// |
-// |This endpoint allows regular users (without admin roles) to discover which dynamic entities
-// |they can interact with for storing personal data via the /my/ENTITY_NAME endpoints.
-// |
-// |Authentication: User must be logged in (no special roles required).
-// |
-// |Use case: Portals and apps can show users what personal data types are available
-// |without needing admin access to view all dynamic entity definitions.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("My-Dynamic-Entities")}""",
-// EmptyBody,
-// MyDynamicEntitiesJsonV600(
-// dynamic_entities = List(
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "customer_preferences",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = true,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[org.json4s.JsonAST.JObject],
-// _links = Some(DynamicEntityLinksJsonV600(
-// related = List(
-// RelatedLinkJsonV600("personal-list", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences", "GET"),
-// RelatedLinkJsonV600("personal-create", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences", "POST"),
-// RelatedLinkJsonV600("personal-read", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"),
-// RelatedLinkJsonV600("personal-update", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"),
-// RelatedLinkJsonV600("personal-delete", s"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE")
-// )
-// ))
-// )
-// )
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagDynamicEntity, apiTagPersonalDynamicEntity, apiTagApi)
-// )
-//
-// lazy val getAvailablePersonalDynamicEntities: OBPEndpoint = {
-// case "personal-dynamic-entities" :: "available" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// // Get all dynamic entities (system and bank level)
-// allDynamicEntities <- Future(
-// NewStyle.function.getDynamicEntities(None, true)
-// )
-// } yield {
-// // Filter to only those with hasPersonalEntity == true
-// val personalEntities: List[DynamicEntityCommons] = allDynamicEntities.filter(_.hasPersonalEntity)
-// (
-// JSONFactory600.createMyDynamicEntitiesJson(personalEntities),
-// HttpCode.`200`(cc.callContext)
-// )
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// verifyUserCredentials,
-// implementedInApiVersion,
-// nameOf(verifyUserCredentials),
-// "POST",
-// "/users/verify-credentials",
-// "Verify User Credentials",
-// s"""Verify a user's credentials (username, password, provider) and return user information if valid.
-// |
-// |This endpoint validates the provided credentials without creating a token or session.
-// |It can be used to verify user credentials in external systems.
-// |
-// |${applicationAccessMessage(true)}
-// |
-// |""",
-// PostVerifyUserCredentialsJsonV600(
-// username = "username",
-// password = "password",
-// provider = Constant.localIdentityProvider
-// ),
-// userJsonV200,
-// List(
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// InvalidLoginCredentials,
-// UsernameHasBeenLocked,
-// UnknownError
-// ),
-// List(apiTagUser),
-// Some(List(canVerifyUserCredentials)),
-// authMode = UserOrApplication
-// )
-//
-// lazy val verifyUserCredentials: OBPEndpoint = {
-// case "users" :: "verify-credentials" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// callContext <- Future.successful(Some(cc))
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the PostVerifyUserCredentialsJsonV600", 400, callContext) {
-// json.extract[PostVerifyUserCredentialsJsonV600]
-// }
-// // Decode the provider in case it's URL-encoded (e.g., "http%3A%2F%2Fexample.com" -> "http://example.com")
-// decodedProvider = URLDecoder.decode(postedData.provider, StandardCharsets.UTF_8)
-// // Validate credentials using the existing AuthUser mechanism
-//
-// resourceUserIdBox = code.model.dataAccess.AuthUser.getResourceUserId(
-// postedData.username, postedData.password, decodedProvider
-// )
-// // Check if account is locked
-// _ <- Helper.booleanToFuture(UsernameHasBeenLocked, 401, callContext) {
-// resourceUserIdBox != Full(code.model.dataAccess.AuthUser.usernameLockedStateCode)
-// }
-// // Check if email is validated
-// _ <- Helper.booleanToFuture(UserEmailNotValidated, 401, callContext) {
-// resourceUserIdBox != Full(code.model.dataAccess.AuthUser.userEmailNotValidatedStateCode)
-// }
-// // Check if credentials are valid
-// resourceUserId <- Future {
-// resourceUserIdBox
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$InvalidLoginCredentials Failed to authenticate user credentials.", 401)
-// }
-// // Get the user object
-// user <- Future {
-// Users.users.vend.getUserByResourceUserId(resourceUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$InvalidLoginCredentials User account not found in system.", 401)
-// }
-// // Verify provider matches if specified and not empty
-// _ <- Helper.booleanToFuture(s"$InvalidLoginCredentials Authentication provider mismatch.", 401, callContext) {
-// decodedProvider.isEmpty || user.provider == decodedProvider
-// }
-// } yield {
-// (JSONFactory200.createUserJSON(user), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// verifyOidcClient,
-// implementedInApiVersion,
-// nameOf(verifyOidcClient),
-// "POST",
-// "/oidc/clients/verify",
-// "Verify OIDC Client",
-// s"""Verifies an OIDC/OAuth2 client's credentials.
-// |
-// |Returns `valid: true` if the client_id and client_secret match an active consumer.
-// |Also returns the consumer_id and redirect_uris for use by the OIDC provider.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// VerifyOidcClientRequestJsonV600(
-// client_id = "abc123def456",
-// client_secret = "supersecret123"
-// ),
-// VerifyOidcClientResponseJsonV600(
-// valid = true,
-// client_id = Some("abc123def456"),
-// consumer_id = Some("7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh"),
-// redirect_uris = Some(List("https://app.example.com/callback"))
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagOIDC, apiTagConsumer, apiTagOAuth),
-// Some(List(canVerifyOidcClient)),
-// authMode = UserOrApplication
-// )
-//
-// lazy val verifyOidcClient: OBPEndpoint = {
-// case "oidc" :: "clients" :: "verify" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the VerifyOidcClientRequestJsonV600", 400, callContext) {
-// json.extract[VerifyOidcClientRequestJsonV600]
-// }
-// consumerBox <- Future {
-// Consumers.consumers.vend.getConsumerByConsumerKey(postedData.client_id)
-// }
-// } yield {
-// consumerBox match {
-// case Full(consumer) if consumer.isActive.get && consumer.secret.get == postedData.client_secret =>
-// val redirectUris = Option(consumer.redirectURL.get)
-// .filter(_.nonEmpty)
-// .map(_.split("[,\\s]+").map(_.trim).filter(_.nonEmpty).toList)
-// (VerifyOidcClientResponseJsonV600(
-// valid = true,
-// client_id = Some(postedData.client_id),
-// consumer_id = Some(consumer.consumerId.get),
-// redirect_uris = redirectUris
-// ), HttpCode.`200`(callContext))
-// case Full(consumer) if !consumer.isActive.get =>
-// logger.warn(s"verifyOidcClient: client_id ${postedData.client_id} exists but is not active (consumer_id: ${consumer.consumerId.get})")
-// (VerifyOidcClientResponseJsonV600(valid = false), HttpCode.`200`(callContext))
-// case _ =>
-// (VerifyOidcClientResponseJsonV600(valid = false), HttpCode.`200`(callContext))
-// }
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getOidcClient,
-// implementedInApiVersion,
-// nameOf(getOidcClient),
-// "GET",
-// "/oidc/clients/CLIENT_ID",
-// "Get OIDC Client",
-// s"""Gets an OIDC/OAuth2 client's metadata by client_id.
-// |
-// |Returns client information including name, consumer_id, redirect_uris, and enabled status.
-// |This endpoint does not verify the client secret - use POST /oidc/clients/verify for authentication.
-// |
-// |${userAuthenticationMessage(true)}
-// |""",
-// EmptyBody,
-// GetOidcClientResponseJsonV600(
-// client_id = "abc123def456",
-// client_name = "My Application",
-// consumer_id = "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
-// redirect_uris = List("https://app.example.com/callback"),
-// enabled = true
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagOIDC, apiTagConsumer, apiTagOAuth),
-// Some(List(canGetOidcClient)),
-// authMode = UserOrApplication
-// )
-//
-// lazy val getOidcClient: OBPEndpoint = {
-// case "oidc" :: "clients" :: clientId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// consumerBox <- Future {
-// Consumers.consumers.vend.getConsumerByConsumerKey(clientId)
-// }
-// consumer <- NewStyle.function.tryons(s"OBP-OIDC-003: Client not found: $clientId", 404, callContext) {
-// consumerBox match {
-// case Full(c) => c
-// case _ => throw new RuntimeException("Client not found")
-// }
-// }
-// } yield {
-// val redirectUris = Option(consumer.redirectURL.get)
-// .filter(_.nonEmpty)
-// .map(_.split("[,\\s]+").map(_.trim).filter(_.nonEmpty).toList)
-// .getOrElse(List.empty)
-// (GetOidcClientResponseJsonV600(
-// client_id = clientId,
-// client_name = consumer.name.get,
-// consumer_id = consumer.consumerId.get,
-// redirect_uris = redirectUris,
-// enabled = consumer.isActive.get
-// ), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Featured API Collections Management Endpoints
-//
-// staticResourceDocs += ResourceDoc(
-// createFeaturedApiCollection,
-// implementedInApiVersion,
-// nameOf(createFeaturedApiCollection),
-// "POST",
-// "/management/api-collections/featured",
-// "Create Featured Api Collection",
-// s"""Add an API Collection to the featured list.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// postFeaturedApiCollectionJsonV600,
-// featuredApiCollectionJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ApiCollectionNotFound,
-// FeaturedApiCollectionAlreadyExists,
-// CreateFeaturedApiCollectionError,
-// UnknownError
-// ),
-// List(apiTagApiCollection, apiTagApi),
-// Some(List(canManageFeaturedApiCollections))
-// )
-//
-// lazy val createFeaturedApiCollection: OBPEndpoint = {
-// case "management" :: "api-collections" :: "featured" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canManageFeaturedApiCollections, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostFeaturedApiCollectionJsonV600", 400, callContext) {
-// json.extract[PostFeaturedApiCollectionJsonV600]
-// }
-// // Verify the API Collection exists and is sharable
-// (apiCollection, callContext) <- NewStyle.function.getApiCollectionById(postJson.api_collection_id, callContext)
-// _ <- Helper.booleanToFuture(s"$ApiCollectionNotFound The API Collection must be sharable to be featured.", cc=callContext) {
-// apiCollection.isSharable
-// }
-// // Check it's not already featured
-// _ <- NewStyle.function.checkFeaturedApiCollectionDoesNotExist(postJson.api_collection_id, callContext)
-// // Create the featured entry
-// (featuredApiCollection, callContext) <- NewStyle.function.createFeaturedApiCollection(
-// postJson.api_collection_id,
-// postJson.sort_order,
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createFeaturedApiCollectionJsonV600(featuredApiCollection), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getFeaturedApiCollectionsAdmin,
-// implementedInApiVersion,
-// nameOf(getFeaturedApiCollectionsAdmin),
-// "GET",
-// "/management/api-collections/featured",
-// "Get Featured Api Collections (Admin)",
-// s"""Get all featured API collections with their sort order (admin view).
-// |
-// |This endpoint returns the featured collections stored in the database with their sort order.
-// |It is intended for administrators to manage the featured list.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// featuredApiCollectionsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagApiCollection, apiTagApi),
-// Some(List(canManageFeaturedApiCollections))
-// )
-//
-// lazy val getFeaturedApiCollectionsAdmin: OBPEndpoint = {
-// case "management" :: "api-collections" :: "featured" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canManageFeaturedApiCollections, callContext)
-// (featuredApiCollections, callContext) <- NewStyle.function.getAllFeaturedApiCollectionsAdmin(callContext)
-// } yield {
-// (JSONFactory600.createFeaturedApiCollectionsJsonV600(featuredApiCollections), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateFeaturedApiCollection,
-// implementedInApiVersion,
-// nameOf(updateFeaturedApiCollection),
-// "PUT",
-// "/management/api-collections/featured/API_COLLECTION_ID",
-// "Update Featured Api Collection",
-// s"""Update the sort order of a featured API collection.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// putFeaturedApiCollectionJsonV600,
-// featuredApiCollectionJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// FeaturedApiCollectionNotFound,
-// UpdateFeaturedApiCollectionError,
-// UnknownError
-// ),
-// List(apiTagApiCollection, apiTagApi),
-// Some(List(canManageFeaturedApiCollections))
-// )
-//
-// lazy val updateFeaturedApiCollection: OBPEndpoint = {
-// case "management" :: "api-collections" :: "featured" :: apiCollectionId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canManageFeaturedApiCollections, callContext)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutFeaturedApiCollectionJsonV600", 400, callContext) {
-// json.extract[PutFeaturedApiCollectionJsonV600]
-// }
-// (updatedFeaturedApiCollection, callContext) <- NewStyle.function.updateFeaturedApiCollection(
-// apiCollectionId,
-// putJson.sort_order,
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createFeaturedApiCollectionJsonV600(updatedFeaturedApiCollection), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteFeaturedApiCollection,
-// implementedInApiVersion,
-// nameOf(deleteFeaturedApiCollection),
-// "DELETE",
-// "/management/api-collections/featured/API_COLLECTION_ID",
-// "Delete Featured Api Collection",
-// s"""Remove an API Collection from the featured list.
-// |
-// |${userAuthenticationMessage(true)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// FeaturedApiCollectionNotFound,
-// DeleteFeaturedApiCollectionError,
-// UnknownError
-// ),
-// List(apiTagApiCollection, apiTagApi),
-// Some(List(canManageFeaturedApiCollections))
-// )
-//
-// lazy val deleteFeaturedApiCollection: OBPEndpoint = {
-// case "management" :: "api-collections" :: "featured" :: apiCollectionId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canManageFeaturedApiCollections, callContext)
-// (_, callContext) <- NewStyle.function.deleteFeaturedApiCollectionByApiCollectionId(apiCollectionId, callContext)
-// } yield {
-// (Full(true), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPopularApis,
-// implementedInApiVersion,
-// nameOf(getPopularApis),
-// "GET",
-// "/api/popular-endpoints",
-// "Get Popular Endpoints",
-// s"""Returns the operation IDs of the 50 most popular endpoints based on usage metrics.
-// |
-// |This endpoint is public and does not require authentication.
-// |
-// |The response contains a simple list of operation_id strings, ordered by popularity (most called first).
-// |
-// |This includes endpoints from all API standards: OBP, Berlin Group, UK Open Banking, STET, Polish API, etc.
-// |
-// |Example operation_id formats:
-// |* OBP: OBPv4.0.0-getBanks
-// |* Berlin Group: BGv1.3-getAccountList
-// |* UK Open Banking: UKv3.1-getAccounts
-// |
-// |""".stripMargin,
-// EmptyBody,
-// PopularApisJsonV600(
-// operation_ids = List(
-// "OBPv4.0.0-getBanks",
-// "OBPv4.0.0-getBank",
-// "BGv1.3-getAccountList"
-// )
-// ),
-// List(
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi)
-// )
-//
-// lazy val getPopularApis: OBPEndpoint = {
-// case "api" :: "popular-endpoints" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// // Get top 50 APIs - use default date range (all time) with limit of 50
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// // Add limit=50 to the query params
-// limitParams = List(OBPLimit(50))
-// (obpQueryParams, _) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// queryParamsWithLimit = obpQueryParams ++ limitParams
-// topApis <- APIMetrics.apiMetrics.vend.getTopApisFuture(queryParamsWithLimit) map {
-// unboxFullOrFail(_, callContext, UnknownError)
-// }
-// } yield {
-// // Build lookup map from partialFunctionName -> operationId
-// // This handles OBP, Berlin Group, UK Open Banking, and other standards correctly
-// val allDocs = APIUtil.getAllResourceDocs
-// val lookupMap: Map[String, String] = allDocs.map { doc =>
-// doc.partialFunctionName -> doc.operationId
-// }.toMap
-//
-// // Convert TopApi to operation_id, looking up correct format for each standard
-// val operationIds = topApis.flatMap { api =>
-// lookupMap.get(api.ImplementedByPartialFunction)
-// .orElse(
-// scala.util.Try(Some(APIUtil.buildOperationId(ApiVersionUtils.valueOf(api.implementedInVersion), api.ImplementedByPartialFunction)))
-// .getOrElse(None)
-// )
-// }
-// (PopularApisJsonV600(operationIds), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConnectorCallCounts,
-// implementedInApiVersion,
-// nameOf(getConnectorCallCounts),
-// "GET",
-// "/management/connector/metrics/counts",
-// "Get Connector Call Counts",
-// s"""Returns per-hour Redis counters for connector outbound and inbound messages.
-// |
-// |This provides real-time visibility into which connector methods are being called
-// |and how many responses (success/failure) are being received.
-// |
-// |Counters automatically reset every hour (rolling window).
-// |The ttl_seconds field shows when the current hour window resets.
-// |
-// |Requires the prop: write_connector_metrics_redis=true
-// |
-// |Redis key format:
-// |
-// |- Outbound (before connector call): {instance}_{env}_connector_outbound_{version}_{connectorName}_{methodName}_PER_HOUR
-// |- Inbound success (after connector call): {instance}_{env}_connector_inbound_{version}_{connectorName}_{methodName}_success_PER_HOUR
-// |- Inbound failure (after connector call): {instance}_{env}_connector_inbound_{version}_{connectorName}_{methodName}_failure_PER_HOUR
-// |
-// |For example: obp_dev_connector_outbound_1_star_getBanks_PER_HOUR
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ConnectorCountsJsonV600(
-// enabled = true,
-// connector_counts = List(
-// ConnectorCountJsonV600(
-// connector_name = "mapped",
-// method_name = "getBank",
-// per_hour_outbound_count = 152,
-// per_hour_inbound_success_count = 150,
-// per_hour_inbound_failure_count = 2,
-// ttl_seconds = 2847
-// )
-// )
-// ),
-// List(
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canReadMetrics))
-// )
-//
-// lazy val getConnectorCallCounts: OBPEndpoint = {
-// case "management" :: "connector" :: "metrics" :: "counts" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canReadMetrics, callContext)
-// } yield {
-// val counts = ConnectorCountsRedis.getAllCounts()
-// val json = ConnectorCountsJsonV600(
-// enabled = ConnectorCountsRedis.isEnabled,
-// connector_counts = counts.map(c => ConnectorCountJsonV600(
-// connector_name = c.connector_name,
-// method_name = c.method_name,
-// per_hour_outbound_count = c.per_hour_outbound_count,
-// per_hour_inbound_success_count = c.per_hour_inbound_success_count,
-// per_hour_inbound_failure_count = c.per_hour_inbound_failure_count,
-// ttl_seconds = c.ttl_seconds
-// ))
-// )
-// (json, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Api Product Endpoints (independent of CBS)
-//
-// staticResourceDocs += ResourceDoc(
-// createApiProduct,
-// implementedInApiVersion,
-// nameOf(createApiProduct),
-// "POST",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE",
-// "Create Api Product",
-// s"""Create an Api Product for the Bank.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// postPutApiProductJsonV600,
-// apiProductJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// CreateApiProductError,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProduct),
-// Some(List(canCreateApiProduct))
-// )
-//
-// lazy val createApiProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateApiProduct, callContext)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostPutApiProductJsonV600", 400, callContext) {
-// json.extract[PostPutApiProductJsonV600]
-// }
-// (apiProduct, callContext) <- NewStyle.function.createOrUpdateApiProduct(
-// bankId.value,
-// apiProductCode,
-// postJson.parent_api_product_code.getOrElse(""),
-// postJson.name,
-// postJson.category.getOrElse(""),
-// postJson.more_info_url.getOrElse(""),
-// postJson.terms_and_conditions_url.getOrElse(""),
-// postJson.description.getOrElse(""),
-// postJson.collection_id.getOrElse(""),
-// postJson.monthly_subscription_currency.getOrElse(""),
-// postJson.monthly_subscription_amount.getOrElse(""),
-// postJson.per_second_call_limit.getOrElse(-1L),
-// postJson.per_minute_call_limit.getOrElse(-1L),
-// postJson.per_hour_call_limit.getOrElse(-1L),
-// postJson.per_day_call_limit.getOrElse(-1L),
-// postJson.per_week_call_limit.getOrElse(-1L),
-// postJson.per_month_call_limit.getOrElse(-1L),
-// postJson.tags.getOrElse(Nil),
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createApiProductJsonV600(apiProduct, None), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createOrUpdateApiProduct,
-// implementedInApiVersion,
-// nameOf(createOrUpdateApiProduct),
-// "PUT",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE",
-// "Create or Update Api Product",
-// s"""Create or Update an Api Product for the Bank.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// postPutApiProductJsonV600,
-// apiProductJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// CreateApiProductError,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProduct),
-// Some(List(canUpdateApiProduct))
-// )
-//
-// lazy val createOrUpdateApiProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateApiProduct, callContext)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostPutApiProductJsonV600", 400, callContext) {
-// json.extract[PostPutApiProductJsonV600]
-// }
-// (apiProduct, callContext) <- NewStyle.function.createOrUpdateApiProduct(
-// bankId.value,
-// apiProductCode,
-// postJson.parent_api_product_code.getOrElse(""),
-// postJson.name,
-// postJson.category.getOrElse(""),
-// postJson.more_info_url.getOrElse(""),
-// postJson.terms_and_conditions_url.getOrElse(""),
-// postJson.description.getOrElse(""),
-// postJson.collection_id.getOrElse(""),
-// postJson.monthly_subscription_currency.getOrElse(""),
-// postJson.monthly_subscription_amount.getOrElse(""),
-// postJson.per_second_call_limit.getOrElse(-1L),
-// postJson.per_minute_call_limit.getOrElse(-1L),
-// postJson.per_hour_call_limit.getOrElse(-1L),
-// postJson.per_day_call_limit.getOrElse(-1L),
-// postJson.per_week_call_limit.getOrElse(-1L),
-// postJson.per_month_call_limit.getOrElse(-1L),
-// postJson.tags.getOrElse(Nil),
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createApiProductJsonV600(apiProduct, None), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getApiProduct,
-// implementedInApiVersion,
-// nameOf(getApiProduct),
-// "GET",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE",
-// "Get Api Product",
-// s"""Get an Api Product by BANK_ID and API_PRODUCT_CODE.
-// |
-// |Returns the Api Product with its attributes.
-// |
-// |${userAuthenticationMessage(!getApiProductsIsPublic)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// apiProductJsonV600,
-// if (getApiProductsIsPublic) List(ApiProductNotFound, UnknownError) else List(UserHasMissingRoles, ApiProductNotFound, UnknownError),
-// List(apiTagApi, apiTagApiProduct),
-// if (getApiProductsIsPublic) None else Some(List(canGetApiProduct))
-// )
-//
-// lazy val getApiProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getApiProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// _ <- if (!getApiProductsIsPublic) {
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetApiProduct, callContext)
-// } yield callContext
-// } else {
-// Future.successful(callContext)
-// }
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (apiProduct, callContext) <- NewStyle.function.getApiProductByBankIdAndCode(bankId.value, apiProductCode, callContext)
-// (attributes, callContext) <- NewStyle.function.getApiProductAttributesByBankIdAndCode(bankId.value, apiProductCode, callContext)
-// } yield {
-// (JSONFactory600.createApiProductJsonV600(apiProduct, Some(attributes)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getApiProducts,
-// implementedInApiVersion,
-// nameOf(getApiProducts),
-// "GET",
-// "/banks/BANK_ID/api-products",
-// "Get Api Products",
-// s"""Get Api Products for the Bank.
-// |
-// |Optional query parameter: `tag` — filter to products that have the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive.
-// |
-// |${userAuthenticationMessage(!getApiProductsIsPublic)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// apiProductsJsonV600,
-// if (getApiProductsIsPublic) List(UnknownError) else List(UserHasMissingRoles, UnknownError),
-// List(apiTagApi, apiTagApiProduct),
-// if (getApiProductsIsPublic) None else Some(List(canGetApiProduct))
-// )
-//
-// lazy val getApiProducts: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getApiProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// _ <- if (!getApiProductsIsPublic) {
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetApiProduct, callContext)
-// } yield callContext
-// } else {
-// Future.successful(callContext)
-// }
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// tagFilter = req.params.get("tag").flatMap(_.headOption).map(_.trim).filter(_.nonEmpty)
-// (apiProducts, callContext) <- NewStyle.function.getApiProductsByBankId(bankId.value, tagFilter, callContext)
-// } yield {
-// (JSONFactory600.createApiProductsJsonV600(apiProducts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllApiProductsV600,
-// implementedInApiVersion,
-// nameOf(getAllApiProductsV600),
-// "GET",
-// "/api-products",
-// "Get Api Products At All Banks",
-// s"""Returns the Api Products across every bank, merged into a single list. Each product carries its `bank_id`.
-// |
-// |Optional query parameter `tag` — filter to products that have the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive.
-// |
-// |${userAuthenticationMessage(!getApiProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// apiProductsJsonV600,
-// List(UnknownError),
-// List(apiTagApi, apiTagApiProduct)
-// )
-//
-// lazy val getAllApiProductsV600: OBPEndpoint = {
-// case "api-products" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getApiProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// tagFilter = req.params.get("tag").flatMap(_.headOption).map(_.trim).filter(_.nonEmpty)
-// resultJson <- {
-// implicit val formats: org.json4s.Formats = org.json4s.DefaultFormats
-// val cacheKey = s"all:${tagFilter.getOrElse("")}"
-// val cacheTTL = APIUtil.getPropsAsIntValue("getAllApiProductsV600.cache.ttl.seconds", 5)
-// val hit = Caching.getApiProductsCache(cacheKey, cacheTTL)
-// .flatMap(s => try Some(com.openbankproject.commons.util.JsonAliases.parse(s).extract[ApiProductsJsonV600]) catch { case _: Throwable => None })
-// hit match {
-// case Some(cached) => Future.successful(cached)
-// case None =>
-// for {
-// (banks, _) <- NewStyle.function.getBanks(callContext).map(t => (t._1, t._2))
-// perBank <- Future.sequence(
-// banks.map(b => NewStyle.function.getApiProductsByBankId(b.bankId.value, tagFilter, callContext).map(_._1))
-// )
-// apiProducts = perBank.flatten
-// } yield {
-// val result = JSONFactory600.createApiProductsJsonV600(apiProducts)
-// Caching.setApiProductsCache(cacheKey, com.openbankproject.commons.util.JsonAliases.compactRender(Extraction.decompose(result)), cacheTTL)
-// result
-// }
-// }
-// }
-// } yield {
-// (resultJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteApiProduct,
-// implementedInApiVersion,
-// nameOf(deleteApiProduct),
-// "DELETE",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE",
-// "Delete Api Product",
-// s"""Delete an Api Product by BANK_ID and API_PRODUCT_CODE.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ApiProductNotFound,
-// DeleteApiProductError,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProduct),
-// Some(List(canDeleteApiProduct))
-// )
-//
-// lazy val deleteApiProduct: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteApiProduct, callContext)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.deleteApiProductAttributesByBankIdAndCode(bankId.value, apiProductCode, callContext)
-// (_, callContext) <- NewStyle.function.deleteApiProduct(bankId.value, apiProductCode, callContext)
-// } yield {
-// (Full(true), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // Financial Product Endpoints (v6.0.0 — adds tag support)
-//
-// staticResourceDocs += ResourceDoc(
-// getProductsV600,
-// implementedInApiVersion,
-// nameOf(getProductsV600),
-// "GET",
-// "/banks/BANK_ID/products",
-// "Get Products",
-// s"""Returns the financial Products offered by the bank specified by BANK_ID. Response includes the new `tags` field.
-// |
-// |Optional query parameter `tag` — filter to products that carry the given tag (case-insensitive). Repeat `tag=` to require multiple tags (e.g. `?tag=featured&tag=new`).
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productsJsonV600,
-// List(
-// BankNotFound,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProductsV600: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2))
-// resultJson <- {
-// // Short TTL is the freshness guarantee; an admin tag change becomes visible within the TTL.
-// // Redis-backed with versioned namespace prefix so the cache shows up on /system/cache/info
-// // and can be invalidated by bumping the namespace version.
-// implicit val formats: org.json4s.Formats = org.json4s.DefaultFormats
-// val cacheKey = APIMethods600.productsCacheKey(bankId.value, params)
-// val cacheTTL = APIUtil.getPropsAsIntValue("getProductsV600.cache.ttl.seconds", 5)
-// val hit = Caching.getFinancialProductsCache(cacheKey, cacheTTL)
-// .flatMap(s => try Some(com.openbankproject.commons.util.JsonAliases.parse(s).extract[ProductsJsonV600]) catch { case _: Throwable => None })
-// hit match {
-// case Some(cached) => Future.successful(cached)
-// case None =>
-// for {
-// (products, _) <- NewStyle.function.getProducts(bankId, params, callContext)
-// } yield {
-// val tagsByCode = ProductTagsProvider.getTagsByProductCodes(bankId, products.map(_.code.value))
-// val result = JSONFactory600.createProductsJsonV600(products, tagsByCode)
-// Caching.setFinancialProductsCache(cacheKey, com.openbankproject.commons.util.JsonAliases.compactRender(Extraction.decompose(result)), cacheTTL)
-// result
-// }
-// }
-// }
-// } yield {
-// (resultJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllProductsV600,
-// implementedInApiVersion,
-// nameOf(getAllProductsV600),
-// "GET",
-// "/products",
-// "Get Products At All Banks",
-// s"""Returns the financial Products offered by every bank this instance knows about, merged into a single list. Each product carries its `bank_id`.
-// |
-// |Optional query parameter `tag` — filter to products that carry the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive. Repeat `tag=` to require multiple tags.
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productsJsonV600,
-// List(UnknownError),
-// List(apiTagProduct)
-// )
-//
-// lazy val getAllProductsV600: OBPEndpoint = {
-// case "products" :: Nil JsonGet req => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2))
-// resultJson <- {
-// implicit val formats: org.json4s.Formats = org.json4s.DefaultFormats
-// val cacheKey = APIMethods600.productsCacheKey("__all__", params)
-// val cacheTTL = APIUtil.getPropsAsIntValue("getAllProductsV600.cache.ttl.seconds", 60)
-// val hit = Caching.getFinancialProductsCache(cacheKey, cacheTTL)
-// .flatMap(s => try Some(com.openbankproject.commons.util.JsonAliases.parse(s).extract[ProductsJsonV600]) catch { case _: Throwable => None })
-// hit match {
-// case Some(cached) => Future.successful(cached)
-// case None =>
-// for {
-// (banks, _) <- NewStyle.function.getBanks(callContext).map(t => (t._1, t._2))
-// // Fan-out server-side: one getProducts call per bank. The whole fan-out is cached
-// // so the per-bank cost is paid once per TTL.
-// perBank <- Future.sequence(
-// banks.map(b => NewStyle.function.getProducts(b.bankId, params, callContext).map(_._1))
-// )
-// products = perBank.flatten
-// } yield {
-// val tagsByBank = banks.map { b =>
-// val codesForBank = products.filter(_.bankId == b.bankId).map(_.code.value)
-// b.bankId.value -> ProductTagsProvider.getTagsByProductCodes(b.bankId, codesForBank)
-// }.toMap
-// val tagsByCode = tagsByBank.values.foldLeft(Map.empty[String, List[String]])(_ ++ _)
-// val result = JSONFactory600.createProductsJsonV600(products, tagsByCode)
-// Caching.setFinancialProductsCache(cacheKey, com.openbankproject.commons.util.JsonAliases.compactRender(Extraction.decompose(result)), cacheTTL)
-// result
-// }
-// }
-// }
-// } yield {
-// (resultJson, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getProductTagsV600,
-// implementedInApiVersion,
-// nameOf(getProductTagsV600),
-// "GET",
-// "/banks/BANK_ID/products/PRODUCT_CODE/tags",
-// "Get Product Tags",
-// s"""Returns the list of tags currently set on the financial Product.
-// |
-// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin,
-// EmptyBody,
-// productTagsJsonV600,
-// List(
-// BankNotFound,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct)
-// )
-//
-// lazy val getProductTagsV600: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: "tags" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getProduct(bankId, productCode, callContext)
-// tags = ProductTagsProvider.getTags(bankId, productCode)
-// } yield {
-// (JSONFactory600.createProductTagsJsonV600(tags), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// val updateProductTagsEntitlements = canUpdateProductTagsAtOneBank :: canUpdateProductTagsAtAnyBank :: Nil
-// val updateProductTagsEntitlementsRequiredText = UserHasMissingRoles + updateProductTagsEntitlements.mkString(" or ")
-//
-// staticResourceDocs += ResourceDoc(
-// updateProductTagsV600,
-// implementedInApiVersion,
-// nameOf(updateProductTagsV600),
-// "PUT",
-// "/banks/BANK_ID/products/PRODUCT_CODE/tags",
-// "Update Product Tags",
-// s"""Replaces the tags on a financial Product. Tags are free-form string labels (e.g. `featured`, `new`, `beta`). Tag matching in queries is case-insensitive.
-// |
-// |Authentication is Required.""".stripMargin,
-// productTagsJsonV600,
-// productTagsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// BankNotFound,
-// ProductNotFoundByProductCode,
-// UnknownError
-// ),
-// List(apiTagProduct),
-// Some(updateProductTagsEntitlements)
-// )
-//
-// lazy val updateProductTagsV600: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: "tags" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = updateProductTagsEntitlementsRequiredText)(bankId.value, u.userId, updateProductTagsEntitlements, callContext)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getProduct(bankId, productCode, callContext)
-// body <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ProductTagsJsonV600", 400, callContext) {
-// json.extract[ProductTagsJsonV600]
-// }
-// updatedTags <- NewStyle.function.tryons(s"$UpdateProductError", 400, callContext) {
-// ProductTagsProvider.setTags(bankId, productCode, body.tags)
-// .openOrThrowException(UpdateProductError)
-// }
-// } yield {
-// (JSONFactory600.createProductTagsJsonV600(updatedTags), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Api Product Attribute Endpoints
-//
-// staticResourceDocs += ResourceDoc(
-// createApiProductAttribute,
-// implementedInApiVersion,
-// nameOf(createApiProductAttribute),
-// "POST",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE/attribute",
-// "Create Api Product Attribute",
-// s"""Create an Api Product Attribute.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// apiProductAttributeJsonV600,
-// apiProductAttributeResponseJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// ApiProductNotFound,
-// CreateApiProductAttributeError,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProductAttribute),
-// Some(List(canCreateApiProductAttribute))
-// )
-//
-// lazy val createApiProductAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: "attribute" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateApiProductAttribute, callContext)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.getApiProductByBankIdAndCode(bankId.value, apiProductCode, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ApiProductAttributeJsonV600", 400, callContext) {
-// json.extract[ApiProductAttributeJsonV600]
-// }
-// (attribute, callContext) <- NewStyle.function.createOrUpdateApiProductAttribute(
-// bankId.value,
-// apiProductCode,
-// None,
-// postJson.name,
-// postJson.`type`,
-// postJson.value,
-// postJson.is_active,
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createApiProductAttributeResponseJsonV600(attribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateApiProductAttribute,
-// implementedInApiVersion,
-// nameOf(updateApiProductAttribute),
-// "PUT",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID",
-// "Update Api Product Attribute",
-// s"""Update an Api Product Attribute.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// apiProductAttributeJsonV600,
-// apiProductAttributeResponseJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// ApiProductNotFound,
-// ApiProductAttributeNotFound,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProductAttribute),
-// Some(List(canUpdateApiProductAttribute))
-// )
-//
-// lazy val updateApiProductAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: "attributes" :: apiProductAttributeId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateApiProductAttribute, callContext)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.getApiProductByBankIdAndCode(bankId.value, apiProductCode, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ApiProductAttributeJsonV600", 400, callContext) {
-// json.extract[ApiProductAttributeJsonV600]
-// }
-// (attribute, callContext) <- NewStyle.function.createOrUpdateApiProductAttribute(
-// bankId.value,
-// apiProductCode,
-// Some(apiProductAttributeId),
-// postJson.name,
-// postJson.`type`,
-// postJson.value,
-// postJson.is_active,
-// callContext
-// )
-// } yield {
-// (JSONFactory600.createApiProductAttributeResponseJsonV600(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getApiProductAttribute,
-// implementedInApiVersion,
-// nameOf(getApiProductAttribute),
-// "GET",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID",
-// "Get Api Product Attribute",
-// s"""Get an Api Product Attribute by API_PRODUCT_ATTRIBUTE_ID.
-// |
-// |${userAuthenticationMessage(!getApiProductsIsPublic)}
-// |
-// |""".stripMargin,
-// EmptyBody,
-// apiProductAttributeResponseJsonV600,
-// if (getApiProductsIsPublic) List(ApiProductAttributeNotFound, UnknownError) else List(UserHasMissingRoles, ApiProductAttributeNotFound, UnknownError),
-// List(apiTagApi, apiTagApiProductAttribute),
-// if (getApiProductsIsPublic) None else Some(List(canGetApiProductAttribute))
-// )
-//
-// lazy val getApiProductAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: "attributes" :: apiProductAttributeId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- getApiProductsIsPublic match {
-// case false => authenticatedAccess(cc)
-// case true => anonymousAccess(cc)
-// }
-// _ <- if (!getApiProductsIsPublic) {
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetApiProductAttribute, callContext)
-// } yield callContext
-// } else {
-// Future.successful(callContext)
-// }
-// (attribute, callContext) <- NewStyle.function.getApiProductAttributeById(apiProductAttributeId, callContext)
-// } yield {
-// (JSONFactory600.createApiProductAttributeResponseJsonV600(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteApiProductAttribute,
-// implementedInApiVersion,
-// nameOf(deleteApiProductAttribute),
-// "DELETE",
-// "/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID",
-// "Delete Api Product Attribute",
-// s"""Delete an Api Product Attribute by API_PRODUCT_ATTRIBUTE_ID.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ApiProductAttributeNotFound,
-// DeleteApiProductAttributeError,
-// UnknownError
-// ),
-// List(apiTagApi, apiTagApiProductAttribute),
-// Some(List(canDeleteApiProductAttribute))
-// )
-//
-// lazy val deleteApiProductAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "api-products" :: apiProductCode :: "attributes" :: apiProductAttributeId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteApiProductAttribute, callContext)
-// (_, callContext) <- NewStyle.function.deleteApiProductAttribute(apiProductAttributeId, callContext)
-// } yield {
-// (Full(true), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConnectorTraces,
-// implementedInApiVersion,
-// nameOf(getConnectorTraces),
-// "GET",
-// "/management/connector/traces",
-// "Get Connector Traces",
-// s"""Get connector traces which capture the full outbound/inbound messages for each connector call.
-// |
-// |Connector tracing must be enabled via the write_connector_trace=true property.
-// |
-// |Filters Part 1.*filtering* parameters to GET /management/connector/traces
-// |
-// |Should be able to filter on the following fields:
-// |
-// |eg: /management/connector/traces?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
-// |
-// |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString
-// |
-// |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString
-// |
-// |3 limit (for pagination: defaults to 1000) eg:limit=2000
-// |
-// |4 offset (for pagination: zero index, defaults to 0) eg: offset=10
-// |
-// |5 connector_name (if null ignore)
-// |
-// |6 function_name (if null ignore)
-// |
-// |7 correlation_id (if null ignore)
-// |
-// |8 bank_id (if null ignore)
-// |
-// |9 user_id (if null ignore)
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// connectorTracesJsonV600,
-// List(
-// InvalidDateFormat,
-// UnknownError
-// ),
-// List(apiTagMetric, apiTagApi),
-// Some(List(canGetConnectorTrace)))
-//
-// lazy val getConnectorTraces: OBPEndpoint = {
-// case "management" :: "connector" :: "traces" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// traces <- Future(ConnectorTraceProvider.getAllConnectorTraces(obpQueryParams))
-// } yield {
-// (JSONFactory600.createConnectorTracesJsonV600(traces), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getConfigProps,
-// implementedInApiVersion,
-// nameOf(getConfigProps),
-// "GET",
-// "/management/config-props",
-// "Get Config Props",
-// s"""Get the active configuration properties and their runtime values.
-// |
-// |This endpoint uses a self-registration mechanism: each time the code calls
-// |getPropsValue, getPropsAsBoolValue, getPropsAsIntValue, or getPropsAsLongValue
-// |with a default value, that property key is registered.
-// |
-// |Only registered properties are returned. The list grows as more code paths are
-// |exercised. Most properties are registered at startup.
-// |
-// |For each property, the value shown is the actual runtime value. If the property
-// |is not explicitly set, the code-defined default is shown.
-// |
-// |The response includes both regular and webui_ properties, sorted alphabetically by key.
-// |
-// |Properties with sensitive keys or values (containing ${APIUtil.sensitiveKeywords.mkString(", ")})
-// |are excluded from the response entirely.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// configPropsJsonV600,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List(canGetConfigProps)))
-//
-// lazy val getConfigProps: OBPEndpoint = {
-// case "management" :: "config-props" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// configProps = getConfigPropsPairs.map { case (key, value) =>
-// ConfigPropJsonV600(key, maskSensitivePropValue(key, value))
-// }
-// } yield {
-// (ListResult("config_props", configProps), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAppDirectory,
-// implementedInApiVersion,
-// nameOf(getAppDirectory),
-// "GET",
-// "/app-directory",
-// "Get App Directory",
-// s"""Get connectivity information for apps in the OBP ecosystem.
-// |
-// |Returns configuration properties that apps (Portal, API Explorer, API Manager,
-// |Sandbox Populator, OIDC, Keycloak, Hola, MCP, Opey) and agents can use to discover
-// |endpoints in the OBP ecosystem.
-// |
-// |Any props starting with public_ and ending with _url are included automatically.
-// |
-// |Known public app URL props:
-// |${APIUtil.publicAppUrlPropNames.mkString(", ")}
-// |
-// |Empty (unconfigured) values are excluded from the response.
-// |
-// |Authentication is NOT Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// appDirectoryJsonV600,
-// List(
-// UnknownError
-// ),
-// List(apiTagApi),
-// Some(List()))
-//
-// lazy val getAppDirectory: OBPEndpoint = {
-// case "app-directory" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, callContext) <- anonymousAccess(cc)
-// directoryProps = getAppDiscoveryPairs.map { case (key, value) =>
-// ConfigPropJsonV600(key, value)
-// }
-// } yield {
-// (ListResult("app_directory", directoryProps), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // Backup Dynamic Entity Endpoints
-//
-// private def computeBackupName(bankId: Option[String], baseName: String): String = {
-// val firstCandidate = s"${baseName}_BAK"
-// if (DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(bankId, firstCandidate).isEmpty) {
-// firstCandidate
-// } else {
-// var suffix = 2
-// var candidate = s"${baseName}_BAK$suffix"
-// while (DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(bankId, candidate).isDefined) {
-// suffix += 1
-// candidate = s"${baseName}_BAK$suffix"
-// }
-// candidate
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// backupSystemDynamicEntity,
-// implementedInApiVersion,
-// nameOf(backupSystemDynamicEntity),
-// "POST",
-// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID/backup",
-// "Backup System Level Dynamic Entity",
-// s"""Create a backup copy of a system level DynamicEntity specified by DYNAMIC_ENTITY_ID.
-// |
-// |This endpoint creates a backup of the dynamic entity definition and all its data records.
-// |The backup entity will be named with a _BAK suffix (e.g. my_entity_BAK).
-// |If a backup with that name already exists, _BAK2, _BAK3 etc. will be used.
-// |
-// |The calling user will be granted CanGetDynamicEntity_`` on the newly created backup entity.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "my_entity_BAK",
-// user_id = "user-456",
-// bank_id = None,
-// has_personal_entity = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "Backup entity", "required": ["name"], "properties": {"name": {"type": "string", "example": "test"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canBackupSystemDynamicEntity))
-// )
-// lazy val backupSystemDynamicEntity: OBPEndpoint = {
-// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: "backup" :: Nil JsonPost _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// backupDynamicEntityMethod(None, dynamicEntityId, cc)
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// backupBankLevelDynamicEntity,
-// implementedInApiVersion,
-// nameOf(backupBankLevelDynamicEntity),
-// "POST",
-// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID/backup",
-// "Backup Bank Level Dynamic Entity",
-// s"""Create a backup copy of a bank level DynamicEntity specified by DYNAMIC_ENTITY_ID.
-// |
-// |This endpoint creates a backup of the dynamic entity definition and all its data records.
-// |The backup entity will be named with a _BAK suffix (e.g. my_entity_BAK).
-// |If a backup with that name already exists, _BAK2, _BAK3 etc. will be used.
-// |
-// |The calling user will be granted CanGetDynamicEntity_`` on the newly created backup entity.
-// |
-// |For more information see ${Glossary.getGlossaryItemLink("Dynamic-Entities")}
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// DynamicEntityDefinitionJsonV600(
-// dynamic_entity_id = "abc-123-def",
-// entity_name = "my_entity_BAK",
-// user_id = "user-456",
-// bank_id = Some("gh.29.uk"),
-// has_personal_entity = false,
-// schema = com.openbankproject.commons.util.JsonAliases.parse("""{"description": "Backup entity", "required": ["name"], "properties": {"name": {"type": "string", "example": "test"}}}""").asInstanceOf[org.json4s.JsonAST.JObject]
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagManageDynamicEntity, apiTagApi),
-// Some(List(canBackupBankLevelDynamicEntity))
-// )
-// lazy val backupBankLevelDynamicEntity: OBPEndpoint = {
-// case "management" :: "banks" :: BankId(bankId) :: "dynamic-entities" :: dynamicEntityId :: "backup" :: Nil JsonPost _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// backupDynamicEntityMethod(Some(bankId.value), dynamicEntityId, cc)
-// }
-// }
-//
-// private def backupDynamicEntityMethod(
-// bankId: Option[String],
-// dynamicEntityId: String,
-// cc: CallContext
-// ) = {
-// for {
-// // Get the dynamic entity definition
-// (entity, _) <- NewStyle.function.getDynamicEntityById(
-// bankId,
-// dynamicEntityId,
-// cc.callContext
-// )
-// // Check CanGetDynamicEntity_ role
-// canGetRole = DynamicEntityInfo.canGetRole(entity.entityName, entity.bankId)
-// _ <- NewStyle.function.hasEntitlement(entity.bankId.getOrElse(""), cc.userId, canGetRole, cc.callContext)
-//
-// // Get all data records for this entity
-// (box, _) <- NewStyle.function.invokeDynamicConnector(
-// GET_ALL,
-// entity.entityName,
-// None,
-// None,
-// entity.bankId,
-// None,
-// None,
-// false,
-// cc.callContext
-// )
-// resultList: JArray = unboxResult(
-// box.asInstanceOf[Box[JArray]],
-// entity.entityName
-// )
-//
-// // Compute backup name with _BAK, _BAK2, _BAK3 etc.
-// backupName = computeBackupName(entity.bankId, entity.entityName)
-//
-// // Perform the backup
-// _ <- Future { backupDynamicEntity(entity, backupName, resultList) }
-//
-// // Grant CanGet role on the backup entity to the calling user
-// backupCanGetRole = DynamicEntityInfo.canGetRole(backupName, entity.bankId)
-// _ <- Future {
-// Entitlement.entitlement.vend.addEntitlement(
-// entity.bankId.getOrElse(""), cc.userId, backupCanGetRole.toString()
-// )
-// }
-//
-// // Fetch the created backup entity to return it
-// backupEntity <- Future {
-// DynamicEntityProvider.connectorMethodProvider.vend
-// .getByEntityName(entity.bankId, backupName)
-// .openOrThrowException("Backup entity not found after creation")
-// }
-// } yield {
-// val commonsData: DynamicEntityCommons = backupEntity
-// (
-// JSONFactory600.createMyDynamicEntitiesJson(List(commonsData)).dynamic_entities.head,
-// HttpCode.`201`(cc.callContext)
-// )
-// }
-// }
-//
-// // --- Account Access Request Endpoints ---
-//
-// staticResourceDocs += ResourceDoc(
-// createAccountAccessRequest,
-// implementedInApiVersion,
-// nameOf(createAccountAccessRequest),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests",
-// "Create Account Access Request",
-// s"""Create a new Account Access Request (maker step in maker/checker workflow).
-// |
-// |The requestor (maker) creates a request to grant a target user access to a specific view on an account.
-// |A business justification is required.
-// |
-// |The request is created with status INITIATED and must be approved or rejected by a different user (checker).
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// JSONFactory600.PostAccountAccessRequestJsonV600(
-// target_user_id = ExampleValue.userIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// business_justification = "Need access to review monthly account statements for audit purposes."
-// ),
-// JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "INITIATED",
-// checker_user_id = "",
-// checker_comment = "",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// BusinessJustificationRequired,
-// AccountAccessRequestAlreadyExists,
-// AccountAccessRequestCannotBeCreated,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// Some(List(canCreateAccountAccessRequestAtOneBank, canCreateAccountAccessRequestAtAnyBank))
-// )
-//
-// lazy val createAccountAccessRequest: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account-access-requests" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canCreateAccountAccessRequestAtOneBank :: canCreateAccountAccessRequestAtAnyBank :: Nil, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${JSONFactory600.PostAccountAccessRequestJsonV600.getClass.getSimpleName}", 400, callContext) {
-// json.extract[JSONFactory600.PostAccountAccessRequestJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = BusinessJustificationRequired, cc = callContext) {
-// postJson.business_justification.trim.nonEmpty
-// }
-// // Validate target user exists
-// (_, callContext) <- NewStyle.function.findByUserId(postJson.target_user_id, callContext)
-// // Check for existing INITIATED request for same user/account/view
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestAlreadyExists, failCode = 409, cc = callContext) {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getByUserAccountView(postJson.target_user_id, bankId.value, accountId.value, postJson.view_id)
-// .isEmpty
-// }
-// // Validate the view exists
-// _ <- if (postJson.is_system_view) {
-// ViewNewStyle.systemView(ViewId(postJson.view_id), callContext).map(_ => ())
-// } else {
-// ViewNewStyle.customView(ViewId(postJson.view_id), BankIdAccountId(bankId, accountId), callContext).map(_ => ())
-// }
-// request <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend.createAccountAccessRequest(
-// bankId.value,
-// accountId.value,
-// postJson.view_id,
-// postJson.is_system_view,
-// u.userId,
-// postJson.target_user_id,
-// postJson.business_justification
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestCannotBeCreated, 400)
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestJsonV600(request), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountAccessRequestsForAccount,
-// implementedInApiVersion,
-// nameOf(getAccountAccessRequestsForAccount),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests",
-// "Get Account Access Requests for Account",
-// s"""Get Account Access Requests for a specific account (checker view).
-// |
-// |Optionally filter by status using the query parameter: ?status=INITIATED
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.AccountAccessRequestsJsonV600(
-// account_access_requests = List(JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "INITIATED",
-// checker_user_id = "",
-// checker_comment = "",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ))
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// $BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// Some(List(canGetAccountAccessRequestsAtOneBank, canGetAccountAccessRequestsAtAnyBank))
-// )
-//
-// lazy val getAccountAccessRequestsForAccount: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account-access-requests" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canGetAccountAccessRequestsAtOneBank :: canGetAccountAccessRequestsAtAnyBank :: Nil, callContext)
-// statusParam = ObpS.param("status")
-// requests <- Future {
-// statusParam match {
-// case Full(status) =>
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getByAccountAndStatus(bankId.value, accountId.value, status)
-// case _ =>
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getByAccount(bankId.value, accountId.value)
-// }
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get account access requests", 400)
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestsJsonV600(requests), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMyAccountAccessRequests,
-// implementedInApiVersion,
-// nameOf(getMyAccountAccessRequests),
-// "GET",
-// "/my/account-access-requests",
-// "Get My Account Access Requests",
-// s"""Get Account Access Requests created by the current user (maker view).
-// |
-// |No special roles are required — a user can always see their own requests.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.AccountAccessRequestsJsonV600(
-// account_access_requests = List(JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "INITIATED",
-// checker_user_id = "",
-// checker_comment = "",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ))
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// None
-// )
-//
-// lazy val getMyAccountAccessRequests: OBPEndpoint = {
-// case "my" :: "account-access-requests" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// requests <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getByRequestorUserId(u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get account access requests", 400)
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestsJsonV600(requests), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountAccessRequestById,
-// implementedInApiVersion,
-// nameOf(getAccountAccessRequestById),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID",
-// "Get Account Access Request by Id",
-// s"""Get a single Account Access Request by its ID.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "INITIATED",
-// checker_user_id = "",
-// checker_comment = "",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// $BankAccountNotFound,
-// AccountAccessRequestNotFound,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// Some(List(canGetAccountAccessRequestsAtOneBank, canGetAccountAccessRequestsAtAnyBank))
-// )
-//
-// lazy val getAccountAccessRequestById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account-access-requests" :: accountAccessRequestId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canGetAccountAccessRequestsAtOneBank :: canGetAccountAccessRequestsAtAnyBank :: Nil, callContext)
-// request <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getById(accountAccessRequestId)
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestNotFound, 404)
-// }
-// // Verify the request belongs to this bank/account
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestNotFound, cc = callContext) {
-// request.bankId == bankId.value && request.accountId == accountId.value
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestJsonV600(request), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// approveAccountAccessRequest,
-// implementedInApiVersion,
-// nameOf(approveAccountAccessRequest),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID/approval",
-// "Approve Account Access Request",
-// s"""Approve an Account Access Request (checker step in maker/checker workflow).
-// |
-// |The checker must be a different user than the maker (requestor). This enforces dual control / maker-checker separation.
-// |
-// |Only requests with status INITIATED can be approved.
-// |
-// |On approval, the system automatically grants the target user access to the specified view.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// JSONFactory600.PostApproveAccountAccessRequestJsonV600(
-// comment = Some("Approved for Q1 audit.")
-// ),
-// JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "APPROVED",
-// checker_user_id = "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// checker_comment = "Approved for Q1 audit.",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// AccountAccessRequestNotFound,
-// AccountAccessRequestStatusNotInitiated,
-// MakerCheckerSameUser,
-// AccountAccessRequestCannotBeUpdated,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// Some(List(canUpdateAccountAccessRequestAtOneBank, canUpdateAccountAccessRequestAtAnyBank))
-// )
-//
-// lazy val approveAccountAccessRequest: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account-access-requests" :: accountAccessRequestId :: "approval" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canUpdateAccountAccessRequestAtOneBank :: canUpdateAccountAccessRequestAtAnyBank :: Nil, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the PostApproveAccountAccessRequestJsonV600", 400, callContext) {
-// json.extract[JSONFactory600.PostApproveAccountAccessRequestJsonV600]
-// }
-// request <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getById(accountAccessRequestId)
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestNotFound, 404)
-// }
-// // Verify the request belongs to this bank/account
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestNotFound, cc = callContext) {
-// request.bankId == bankId.value && request.accountId == accountId.value
-// }
-// // Only INITIATED requests can be approved
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestStatusNotInitiated, cc = callContext) {
-// request.status == com.openbankproject.commons.model.enums.AccountAccessRequestStatus.INITIATED.toString
-// }
-// // Maker/checker separation: checker must not be the requestor
-// _ <- Helper.booleanToFuture(failMsg = MakerCheckerSameUser, cc = callContext) {
-// u.userId != request.requestorUserId
-// }
-// // Get the target user
-// (targetUser, callContext) <- NewStyle.function.findByUserId(request.targetUserId, callContext)
-// // Grant view access
-// _ <- if (request.isSystemView) {
-// ViewNewStyle.systemView(ViewId(request.viewId), callContext).flatMap { view =>
-// ViewNewStyle.grantAccessToSystemView(bankId, accountId, view, targetUser, callContext)
-// }
-// } else {
-// ViewNewStyle.customView(ViewId(request.viewId), BankIdAccountId(bankId, accountId), callContext).flatMap { view =>
-// ViewNewStyle.grantAccessToCustomView(view, targetUser, callContext)
-// }
-// }
-// // Update the request status to APPROVED
-// updatedRequest <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend.updateStatus(
-// accountAccessRequestId,
-// com.openbankproject.commons.model.enums.AccountAccessRequestStatus.APPROVED.toString,
-// u.userId,
-// postJson.comment.getOrElse("")
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestCannotBeUpdated, 400)
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestJsonV600(updatedRequest), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// rejectAccountAccessRequest,
-// implementedInApiVersion,
-// nameOf(rejectAccountAccessRequest),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID/rejection",
-// "Reject Account Access Request",
-// s"""Reject an Account Access Request (checker step in maker/checker workflow).
-// |
-// |The checker must be a different user than the maker (requestor). This enforces dual control / maker-checker separation.
-// |
-// |Only requests with status INITIATED can be rejected.
-// |
-// |A comment is required when rejecting a request.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// JSONFactory600.PostRejectAccountAccessRequestJsonV600(
-// comment = "Insufficient business justification provided."
-// ),
-// JSONFactory600.AccountAccessRequestJsonV600(
-// account_access_request_id = "b4e0352a-9a0f-4bfa-b30b-9003aa467f51",
-// bank_id = ExampleValue.bankIdExample.value,
-// account_id = ExampleValue.accountIdExample.value,
-// view_id = ExampleValue.viewIdExample.value,
-// is_system_view = true,
-// requestor_user_id = ExampleValue.userIdExample.value,
-// target_user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2",
-// business_justification = "Need access to review monthly account statements for audit purposes.",
-// status = "REJECTED",
-// checker_user_id = "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
-// checker_comment = "Insufficient business justification provided.",
-// created = APIUtil.DateWithMsExampleObject,
-// updated = APIUtil.DateWithMsExampleObject
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// InvalidJsonFormat,
-// $BankNotFound,
-// $BankAccountNotFound,
-// AccountAccessRequestNotFound,
-// AccountAccessRequestStatusNotInitiated,
-// MakerCheckerSameUser,
-// CheckerCommentRequiredForRejection,
-// AccountAccessRequestCannotBeUpdated,
-// UnknownError
-// ),
-// List(apiTagAccountAccessRequest),
-// Some(List(canUpdateAccountAccessRequestAtOneBank, canUpdateAccountAccessRequestAtAnyBank))
-// )
-//
-// lazy val rejectAccountAccessRequest: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "account-access-requests" :: accountAccessRequestId :: "rejection" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canUpdateAccountAccessRequestAtOneBank :: canUpdateAccountAccessRequestAtAnyBank :: Nil, callContext)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the PostRejectAccountAccessRequestJsonV600", 400, callContext) {
-// json.extract[JSONFactory600.PostRejectAccountAccessRequestJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = CheckerCommentRequiredForRejection, cc = callContext) {
-// postJson.comment.trim.nonEmpty
-// }
-// request <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend
-// .getById(accountAccessRequestId)
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestNotFound, 404)
-// }
-// // Verify the request belongs to this bank/account
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestNotFound, cc = callContext) {
-// request.bankId == bankId.value && request.accountId == accountId.value
-// }
-// // Only INITIATED requests can be rejected
-// _ <- Helper.booleanToFuture(failMsg = AccountAccessRequestStatusNotInitiated, cc = callContext) {
-// request.status == com.openbankproject.commons.model.enums.AccountAccessRequestStatus.INITIATED.toString
-// }
-// // Maker/checker separation: checker must not be the requestor
-// _ <- Helper.booleanToFuture(failMsg = MakerCheckerSameUser, cc = callContext) {
-// u.userId != request.requestorUserId
-// }
-// // Update the request status to REJECTED
-// updatedRequest <- Future {
-// code.accountaccessrequest.AccountAccessRequestTrait.accountAccessRequest.vend.updateStatus(
-// accountAccessRequestId,
-// com.openbankproject.commons.model.enums.AccountAccessRequestStatus.REJECTED.toString,
-// u.userId,
-// postJson.comment
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, AccountAccessRequestCannotBeUpdated, 400)
-// }
-// } yield {
-// (JSONFactory600.createAccountAccessRequestJsonV600(updatedRequest), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-//
-// // ---- Signal Channels (Redis-backed short-lived messaging for AI agents and other consumers) ----
-//
-// staticResourceDocs += ResourceDoc(
-// publishSignalMessage,
-// implementedInApiVersion,
-// nameOf(publishSignalMessage),
-// "POST",
-// "/signal/channels/CHANNEL_NAME/messages",
-// "Publish Signal Message",
-// s"""Publish a message to a signal channel.
-// |
-// |Signal channels provide short-lived, Redis-backed messaging for lightweight coordination between
-// |AI agents and other OBP consumers. Messages are not persisted to a database.
-// |
-// |Channels are auto-created on first publish and expire after a configurable TTL (default 1 hour).
-// |Messages are capped at a configurable maximum per channel (default 1000).
-// |
-// |The payload field accepts any valid JSON content.
-// |
-// |Set to_user_id to send a private message visible only to the sender and recipient.
-// |Leave to_user_id empty for a broadcast message visible to all channel readers.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// postSignalMessageJsonV600,
-// signalMessagePublishedJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// InvalidSignalChannelName,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel))
-//
-// lazy val publishSignalMessage: OBPEndpoint = {
-// case "signal" :: "channels" :: channelName :: "messages" :: Nil JsonPost json -> _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the PostSignalMessageJsonV600", 400, callContext) {
-// json.extract[PostSignalMessageJsonV600]
-// }
-// _ <- Helper.booleanToFuture(failMsg = InvalidSignalChannelName, cc = callContext) {
-// RedisMessaging.validateChannelName(channelName)
-// }
-// channelMessageCount <- Future {
-// val consumerId: String = cc.consumer match {
-// case Full(c) => c.consumerId.get
-// case _ => ""
-// }
-// val messageId = randomUUID().toString
-// val sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-// sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// val timestamp = sdf.format(new java.util.Date())
-// val messageEnvelope = SignalMessageJsonV600(
-// message_id = messageId,
-// channel_name = channelName,
-// sender_consumer_id = consumerId,
-// sender_user_id = u.userId,
-// to_user_id = postJson.to_user_id,
-// timestamp = timestamp,
-// message_type = postJson.message_type.getOrElse(""),
-// payload = postJson.payload
-// )
-// val messageJsonString = com.openbankproject.commons.util.JsonAliases.compactRender(org.json4s.Extraction.decompose(messageEnvelope))
-// val count = RedisMessaging.publishMessage(channelName, messageJsonString)
-// (messageId, timestamp, count)
-// }
-// } yield {
-// val (messageId, timestamp, count) = channelMessageCount
-// val response = SignalMessagePublishedJsonV600(
-// message_id = messageId,
-// channel_name = channelName,
-// timestamp = timestamp,
-// channel_message_count = count
-// )
-// (response, HttpCode.`201`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getSignalMessages,
-// implementedInApiVersion,
-// nameOf(getSignalMessages),
-// "GET",
-// "/signal/channels/CHANNEL_NAME/messages",
-// "Get Signal Messages",
-// s"""Fetch messages from a signal channel with offset/limit pagination.
-// |
-// |Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery
-// |and coordination, but usable by any authenticated OBP consumer.
-// |
-// |Messages are returned oldest-first.
-// |
-// |Privacy filtering is applied server-side: you will only see broadcast messages (no to_user_id)
-// |and private messages addressed to you (to_user_id matches your user ID) or sent by you.
-// |
-// |Use the offset parameter to poll for new messages by tracking your position.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// signalMessagesJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidSignalChannelName,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel))
-//
-// lazy val getSignalMessages: OBPEndpoint = {
-// case "signal" :: "channels" :: channelName :: "messages" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = InvalidSignalChannelName, cc = callContext) {
-// RedisMessaging.validateChannelName(channelName)
-// }
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
-// limit = obpQueryParams.collectFirst { case OBPLimit(value) => value }.getOrElse(50)
-// offset = obpQueryParams.collectFirst { case OBPOffset(value) => value }.getOrElse(0)
-// (rawMessages, totalCount) <- Future {
-// RedisMessaging.fetchMessages(channelName, offset, limit)
-// }
-// } yield {
-// val parsedMessages: List[SignalMessageJsonV600] = rawMessages.flatMap { msgStr =>
-// scala.util.Try(com.openbankproject.commons.util.JsonAliases.parse(msgStr).extract[SignalMessageJsonV600]).toOption
-// }
-// // Privacy filter: only show broadcasts (to_user_id is None) and messages to/from this user
-// val filteredMessages = parsedMessages.filter { msg =>
-// msg.to_user_id.isEmpty ||
-// msg.to_user_id.contains(u.userId) ||
-// msg.sender_user_id == u.userId
-// }
-// val response = SignalMessagesJsonV600(
-// channel_name = channelName,
-// messages = filteredMessages,
-// total_count = totalCount,
-// has_more = (offset + limit) < totalCount
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getSignalChannels,
-// implementedInApiVersion,
-// nameOf(getSignalChannels),
-// "GET",
-// "/signal/channels",
-// "List Signal Channels",
-// s"""Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.
-// |Messages are ephemeral and will expire after the configured TTL (default 1 hour).
-// |
-// |This endpoint lists active signal channels.
-// |Only channels that contain at least one broadcast message (no to_user_id) are listed.
-// |Private-only channels are not shown.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// signalChannelsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel))
-//
-// lazy val getSignalChannels: OBPEndpoint = {
-// case "signal" :: "channels" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// channelNames <- Future {
-// RedisMessaging.listChannels()
-// }
-// channelsWithInfo <- Future.sequence(
-// channelNames.map { name =>
-// Future {
-// RedisMessaging.channelInfo(name).map { case (count, ttl) =>
-// // Check if channel has any broadcast messages
-// val (messages, _) = RedisMessaging.fetchMessages(name, 0, count.toInt)
-// val hasBroadcast = messages.exists { msgStr =>
-// scala.util.Try {
-// val msg = com.openbankproject.commons.util.JsonAliases.parse(msgStr).extract[SignalMessageJsonV600]
-// msg.to_user_id.isEmpty
-// }.getOrElse(false)
-// }
-// (name, count, ttl, hasBroadcast)
-// }
-// }
-// }
-// )
-// } yield {
-// val channels = channelsWithInfo.flatten
-// .filter(_._4) // Only channels with broadcast messages
-// .map { case (name, count, ttl, _) =>
-// SignalChannelInfoJsonV600(
-// channel_name = name,
-// message_count = count,
-// ttl_seconds = ttl
-// )
-// }
-// (SignalChannelsJsonV600(channels), HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getSignalChannelInfo,
-// implementedInApiVersion,
-// nameOf(getSignalChannelInfo),
-// "GET",
-// "/signal/channels/CHANNEL_NAME/info",
-// "Get Signal Channel Info",
-// s"""Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.
-// |Messages are ephemeral and will expire after the configured TTL (default 1 hour).
-// |
-// |This endpoint returns metadata about a signal channel including the current message count and remaining TTL in seconds.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// signalChannelInfoJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidSignalChannelName,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel))
-//
-// lazy val getSignalChannelInfo: OBPEndpoint = {
-// case "signal" :: "channels" :: channelName :: "info" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = InvalidSignalChannelName, cc = callContext) {
-// RedisMessaging.validateChannelName(channelName)
-// }
-// info <- Future {
-// RedisMessaging.channelInfo(channelName)
-// }
-// (count, ttl) <- info match {
-// case Some((c, t)) => Future.successful((c, t))
-// case None => Future.failed(new RuntimeException(s"Channel '$channelName' not found"))
-// }
-// } yield {
-// val response = SignalChannelInfoJsonV600(
-// channel_name = channelName,
-// message_count = count,
-// ttl_seconds = ttl
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSignalChannel,
-// implementedInApiVersion,
-// nameOf(deleteSignalChannel),
-// "DELETE",
-// "/signal/channels/CHANNEL_NAME",
-// "Delete Signal Channel",
-// s"""Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.
-// |Messages are ephemeral and will expire after the configured TTL (default 1 hour).
-// |
-// |This endpoint deletes a signal channel and all its messages immediately.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// signalChannelDeletedJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidSignalChannelName,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel))
-//
-// staticResourceDocs += ResourceDoc(
-// getSignalStats,
-// implementedInApiVersion,
-// nameOf(getSignalStats),
-// "GET",
-// "/signal/channels/stats",
-// "Get Signal Channel Stats",
-// s"""Returns statistics for all signal channels, including private-only channels.
-// |
-// |Unlike the List Signal Channels endpoint, this does not filter out private-only channels.
-// |It provides a complete view of all active channels with message counts and TTL info.
-// |
-// |Authentication is Required.
-// |
-// |""".stripMargin,
-// EmptyBody,
-// signalStatsJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel),
-// Some(List(canGetSignalStats)))
-//
-// lazy val getSignalStats: OBPEndpoint = {
-// case "signal" :: "channels" :: "stats" :: Nil JsonGet _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// channelNames <- Future {
-// RedisMessaging.listChannels()
-// }
-// channelsWithInfo <- Future.sequence(
-// channelNames.map { name =>
-// Future {
-// RedisMessaging.channelInfo(name).map { case (count, ttl) =>
-// SignalChannelInfoJsonV600(
-// channel_name = name,
-// message_count = count,
-// ttl_seconds = ttl
-// )
-// }
-// }
-// }
-// )
-// } yield {
-// val channels = channelsWithInfo.flatten
-// val totalMessages = channels.map(_.message_count).sum
-// val response = SignalStatsJsonV600(
-// total_channels = channels.size,
-// total_messages = totalMessages,
-// channels = channels
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-//
-//
-// lazy val deleteSignalChannel: OBPEndpoint = {
-// case "signal" :: "channels" :: channelName :: Nil JsonDelete _ =>
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Helper.booleanToFuture(failMsg = InvalidSignalChannelName, cc = callContext) {
-// RedisMessaging.validateChannelName(channelName)
-// }
-// deleted <- Future {
-// RedisMessaging.deleteChannel(channelName)
-// }
-// } yield {
-// val response = SignalChannelDeletedJsonV600(
-// channel_name = channelName,
-// deleted = deleted
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAccountDirectory,
-// implementedInApiVersion,
-// nameOf(getAccountDirectory),
-// "GET",
-// "/banks/BANK_ID/account-directory",
-// "Get Account Directory at Bank",
-// s"""Returns a list of accounts at the bank with identifiers and metadata.
-// |
-// |This endpoint is designed for management UIs that need to list accounts
-// |without exposing sensitive data (balance and owners are excluded).
-// |
-// |The response includes: account_id, bank_id, label, account_number, account_type, branch_id,
-// |account_routings, account_attributes and view_ids.
-// |
-// |${urlParametersDocument(true, false)}
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.AccountDirectoryJsonV600(
-// accounts = List(JSONFactory600.AccountDirectoryItemJsonV600(
-// account_id = ExampleValue.accountIdExample.value,
-// bank_id = ExampleValue.bankIdExample.value,
-// label = "My Account",
-// account_number = "123456789",
-// account_type = "CURRENT",
-// branch_id = "BRANCH_1",
-// account_routings = List(FastFirehoseRoutings(bank_id = ExampleValue.bankIdExample.value, account_id = ExampleValue.accountIdExample.value)),
-// account_attributes = List(FastFirehoseAttributes(`type` = "STRING", code = "OVERDRAFT_LIMIT", value = "1000")),
-// view_ids = List("owner")
-// ))
-// ),
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount),
-// Some(List(canGetAccountDirectoryAtOneBank))
-// )
-//
-// lazy val getAccountDirectory: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "account-directory" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.getBank(bankId, callContext)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetAccountDirectoryAtOneBank, callContext)
-// allowedParams = List("limit", "offset", "sort_direction")
-// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
-// (obpQueryParams, callContext) <- NewStyle.function.createObpParams(httpParams, allowedParams, callContext)
-// (accounts, callContext) <- NewStyle.function.getAccountDirectory(bankId, obpQueryParams, callContext)
-// } yield {
-// val viewsPerAccount: Map[BankIdAccountId, List[String]] = accounts.map { a =>
-// val bankIdAccountId = BankIdAccountId(BankId(a.bankId), AccountId(a.id))
-// val viewIds = Views.views.vend.availableViewsForAccount(bankIdAccountId).map(_.viewId.value)
-// bankIdAccountId -> viewIds
-// }.toMap
-// (JSONFactory600.createAccountDirectoryJsonV600(accounts, viewsPerAccount), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// hasAccountAccess,
-// implementedInApiVersion,
-// nameOf(hasAccountAccess),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/has-account-access",
-// "Has Account Access",
-// s"""Check whether the authenticated user has access to a specific view on a specific account.
-// |
-// |Returns a boolean `has_account_access` along with the `access_source` (currently "ACCOUNT_ACCESS")
-// |and the `account_access_id` (primary key of the AccountAccess record).
-// |
-// |If the user does not have access, `has_account_access` is false and the other fields are empty strings.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JSONFactory600.HasAccountAccessJsonV600(
-// has_account_access = true,
-// access_source = "ACCOUNT_ACCESS",
-// account_access_id = ExampleValue.uuidExample.value,
-// abac_rule_id = ""
-// ),
-// List(
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagView, apiTagAccount)
-// )
-//
-// lazy val hasAccountAccess: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "has-account-access" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// bankIdAccountId = BankIdAccountId(bankId, accountId)
-// _ <- Future {
-// Views.views.vend.customViewFuture(viewId, bankIdAccountId).flatMap {
-// case Full(v) => Future.successful(Full(v))
-// case _ => Views.views.vend.systemViewFuture(viewId)
-// }
-// }.flatten.map {
-// unboxFullOrFail(_, callContext, s"$ViewNotFound Current ViewId is ${viewId.value}")
-// }
-// accountAccessBox <- Future {
-// AccountAccess.findByBankIdAccountIdViewIdUserPrimaryKey(
-// bankId, accountId, viewId, u.userPrimaryKey
-// )
-// }
-// } yield {
-// val response = accountAccessBox match {
-// case Full(aa) =>
-// JSONFactory600.HasAccountAccessJsonV600(
-// has_account_access = true,
-// access_source = "ACCOUNT_ACCESS",
-// account_access_id = aa.id.get.toString,
-// abac_rule_id = ""
-// )
-// case _ =>
-// JSONFactory600.HasAccountAccessJsonV600(
-// has_account_access = false,
-// access_source = "",
-// account_access_id = "",
-// abac_rule_id = ""
-// )
-// }
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getUsersWithAccountAccess,
-// implementedInApiVersion,
-// nameOf(getUsersWithAccountAccess),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/users-with-access",
-// "Get Users With Account Access",
-// s"""Get all users who have access to a specific view on a specific account, and how that access was granted.
-// |
-// |This endpoint combines both traditional AccountAccess records and ABAC (Attribute-Based Access Control)
-// |evaluation to provide a complete picture of who can access the specified view.
-// |
-// |Each user entry includes an access_source indicating how access was granted
-// |(either "ACCOUNT_ACCESS" for direct grants or "ABAC" for rule-based access).
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// UsersWithViewAccessJsonV600(
-// users = List(UserWithViewAccessJsonV600(
-// user_id = ExampleValue.userIdExample.value,
-// username = "robert.x.smith.test",
-// email = "robert.x@example.com",
-// provider = "https://apisandbox.openbankproject.com",
-// access_source = "ACCOUNT_ACCESS"
-// ))
-// ),
-// List(
-// $BankNotFound,
-// BankAccountNotFound,
-// UnknownError
-// ),
-// List(apiTagAccount, apiTagView),
-// Some(List(canSeeAccountAccessForAnyUser))
-// )
-//
-// lazy val getUsersWithAccountAccess: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "users-with-access" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
-// (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
-// bankIdAccountId = BankIdAccountId(bankId, accountId)
-//
-// // Validate the view exists
-// _ <- Future {
-// Views.views.vend.customViewFuture(viewId, bankIdAccountId).flatMap {
-// case Full(v) => Future.successful(Full(v))
-// case _ => Views.views.vend.systemViewFuture(viewId)
-// }
-// }.flatten.map {
-// unboxFullOrFail(_, callContext, s"$ViewNotFound Current ViewId is ${viewId.value}")
-// }
-//
-// // Step A: Get traditional AccountAccess users for this view
-// permissions <- Future(Views.views.vend.permissions(bankIdAccountId))
-// accountAccessUsers: List[UserWithViewAccessJsonV600] = permissions.flatMap { perm =>
-// if (perm.views.exists(_.viewId == viewId)) {
-// Some(UserWithViewAccessJsonV600(
-// user_id = perm.user.userId,
-// username = perm.user.name,
-// email = perm.user.emailAddress,
-// provider = perm.user.provider,
-// access_source = "ACCOUNT_ACCESS"
-// ))
-// } else None
-// }
-// accountAccessUserIds = accountAccessUsers.map(_.user_id).toSet
-//
-// // Step B: ABAC evaluation — always report ABAC access regardless of
-// // allow_abac_account_access prop. This endpoint reports the truth about
-// // who has access, it does not enforce access.
-// abacUsers <- {
-// // Find users with CanExecuteAbacRule entitlement
-// val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString)
-// .getOrElse(Nil)
-// val abacUserIds = abacEntitlements.map(_.userId).distinct
-// .filterNot(accountAccessUserIds.contains) // Skip users already covered by AccountAccess
-// logger.info(s"getUsersWithAccountAccess says: view=${viewId.value} abacUserIds to evaluate=$abacUserIds")
-//
-// if (abacUserIds.isEmpty) {
-// logger.info("getUsersWithAccountAccess says: No ABAC users to evaluate")
-// Future.successful(List.empty[UserWithViewAccessJsonV600])
-// } else {
-// for {
-// users <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds)
-// _ = logger.info(s"getUsersWithAccountAccess says: Resolved ${users.size} ABAC users: ${users.map(u => s"${u.userId}/${u.name}").mkString(", ")}")
-//
-// abacEvaluations <- Future.sequence(
-// users.map { user =>
-// callContext match {
-// case Some(cc) =>
-// logger.info(s"getUsersWithAccountAccess says: Evaluating user=${user.userId}/${user.name} view=${viewId.value} bank=${bankId.value} account=${accountId.value}")
-// AbacRuleEngine.executeRulesByPolicyDetailed(
-// policy = ABAC_POLICY_ACCOUNT_ACCESS,
-// authenticatedUserId = user.userId,
-// callContext = cc,
-// bankId = Some(bankId.value),
-// accountId = Some(accountId.value),
-// viewId = Some(viewId.value)
-// ).map { result =>
-// logger.info(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${viewId.value} result=$result")
-// result match {
-// case Full((true, _)) => Some(UserWithViewAccessJsonV600(
-// user_id = user.userId,
-// username = user.name,
-// email = user.emailAddress,
-// provider = user.provider,
-// access_source = "ABAC"
-// ))
-// case _ => None
-// }
-// }.recover { case ex =>
-// logger.error(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${viewId.value} EXCEPTION: ${ex.getMessage}", ex)
-// None
-// }
-// case None =>
-// logger.warn("getUsersWithAccountAccess says: callContext is None, skipping ABAC evaluation")
-// Future.successful(None)
-// }
-// }
-// )
-// } yield abacEvaluations.flatten
-// }
-// }
-// } yield {
-// val response = UsersWithViewAccessJsonV600(
-// users = accountAccessUsers ++ abacUsers
-// )
-// (response, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getPrivateAccountByIdFull,
-// implementedInApiVersion,
-// nameOf(getPrivateAccountByIdFull),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account",
-// "Get Account by Id (Full)",
-// """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):
-// |
-// |* Number
-// |* Owners
-// |* Type
-// |* Balance
-// |* Available views (sorted by view_name)
-// |
-// |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).
-// |
-// |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.
-// |This call provides balance and other account information via delegated authentication using OAuth.
-// |
-// |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.
-// |""".stripMargin,
-// EmptyBody,
-// ModeratedAccountJSON600(
-// id = "5995d6a2-01b3-423c-a173-5481df49bdaf",
-// label = "NoneLabel",
-// number = "123",
-// owners = List(userJSONV121),
-// product_code = ExampleValue.productCodeExample.value,
-// balance = amountOfMoneyJsonV121,
-// views_available = List(ViewJsonV600(
-// bank_id = "",
-// account_id = "",
-// view_id = "owner",
-// view_name = "Owner",
-// description = "The owner of the account",
-// metadata_view = "owner",
-// is_public = false,
-// is_system = true,
-// is_firehose = Some(false),
-// alias = "private",
-// hide_metadata_if_alias_used = false,
-// can_grant_access_to_views = List("owner"),
-// can_revoke_access_to_views = List("owner"),
-// allowed_actions = List("can_see_transaction_amount", "can_see_bank_account_balance")
-// )),
-// bank_id = ExampleValue.bankIdExample.value,
-// account_routings = List(accountRoutingJsonV121),
-// account_attributes = List(accountAttributeResponseJson),
-// tags = List(accountTagJSON)
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// $BankAccountNotFound,
-// $UserNoPermissionAccessView,
-// UnknownError
-// ),
-// apiTagAccount :: Nil
-// )
-//
-// lazy val getPrivateAccountByIdFull: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(
-// accountId
-// ) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (user @ Full(u), _, account, view, callContext) <-
-// SS.userBankAccountView
-// moderatedAccount <- NewStyle.function.moderatedBankAccountCore(
-// account,
-// view,
-// user,
-// callContext
-// )
-// (accountAttributes, callContext) <- NewStyle.function
-// .getAccountAttributesByAccount(
-// bankId,
-// accountId,
-// callContext: Option[CallContext]
-// )
-// } yield {
-// val availableViews =
-// Views.views.vend.privateViewsUserCanAccessForAccount(
-// u,
-// BankIdAccountId(account.bankId, account.accountId)
-// )
-// val viewsAvailable =
-// availableViews.map(JSONFactory600.createViewJsonV600).sortBy(_.view_name)
-// val tags = Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId)
-// (
-// createBankAccountJSON600(
-// moderatedAccount,
-// viewsAvailable,
-// accountAttributes,
-// tags
-// ),
-// HttpCode.`200`(callContext)
-// )
-// }
-// }
-// }
-//
-//
-// // ========== Mandate Endpoints ==========
-//
-// staticResourceDocs += ResourceDoc(
-// createMandate,
-// implementedInApiVersion,
-// nameOf(createMandate),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/mandates",
-// "Create Mandate",
-// s"""Create a new mandate for a bank account.
-// |
-// |A mandate is a legal document that defines who can operate an account, what they can do,
-// |and under what conditions (e.g., signatory requirements, amount thresholds).
-// |
-// |Mandates tie together OBP constructs such as Views, ABAC Rules, Signatory Panels,
-// |and Challenges into a coherent authorization policy.
-// |
-// |**Status values:** ACTIVE, SUSPENDED, EXPIRED, DRAFT
-// |
-// |**Date format:** yyyy-MM-dd'T'HH:mm:ss'Z' (UTC)
-// |
-// |Authentication is Required
-// |""",
-// CreateMandateJsonV600(
-// customer_id = "customer-id-123",
-// mandate_name = "ACME Corp Operating Account Authority",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "The following persons are authorised to operate this account...",
-// description = "Payment and account access authority for ACME Corp",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z"
-// ),
-// MandateJsonV600(
-// mandate_id = "mandate-id-123",
-// bank_id = "gh.29.uk",
-// account_id = "8ca8a7e4-6d02",
-// customer_id = "customer-id-123",
-// mandate_name = "ACME Corp Operating Account Authority",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "The following persons are authorised to operate this account...",
-// description = "Payment and account access authority for ACME Corp",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z",
-// created_by_user_id = "user-id-123",
-// updated_by_user_id = "user-id-123"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canCreateMandate))
-// )
-//
-// lazy val createMandate: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "mandates" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// createJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[CreateMandateJsonV600]
-// }
-// validFrom <- NewStyle.function.tryons(s"$InvalidDateFormat valid_from must be in yyyy-MM-dd'T'HH:mm:ss'Z' format", 400, cc.callContext) {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(createJson.valid_from)
-// }
-// validTo <- NewStyle.function.tryons(s"$InvalidDateFormat valid_to must be in yyyy-MM-dd'T'HH:mm:ss'Z' format", 400, cc.callContext) {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(createJson.valid_to)
-// }
-// (mandate, callContext) <- Connector.connector.vend.createMandate(
-// bankId,
-// accountId,
-// createJson.customer_id,
-// createJson.mandate_name,
-// createJson.mandate_reference,
-// createJson.legal_text,
-// createJson.description,
-// createJson.status,
-// validFrom,
-// validTo,
-// cc.userId,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not create mandate"), i._2)
-// }
-// } yield {
-// (createMandateJsonV600(mandate), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMandates,
-// implementedInApiVersion,
-// nameOf(getMandates),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/mandates",
-// "Get Mandates for Account",
-// s"""Get all mandates for a bank account.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// MandatesJsonV600(List(MandateJsonV600(
-// mandate_id = "mandate-id-123",
-// bank_id = "gh.29.uk",
-// account_id = "8ca8a7e4-6d02",
-// customer_id = "customer-id-123",
-// mandate_name = "ACME Corp Operating Account Authority",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "The following persons are authorised...",
-// description = "Payment authority for ACME Corp",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z",
-// created_by_user_id = "user-id-123",
-// updated_by_user_id = "user-id-123"
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetMandate))
-// )
-//
-// lazy val getMandates: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "mandates" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (mandates, callContext) <- Connector.connector.vend.getMandatesByBankAndAccount(
-// bankId, accountId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not get mandates"), i._2)
-// }
-// } yield {
-// (createMandatesJsonV600(mandates), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMandate,
-// implementedInApiVersion,
-// nameOf(getMandate),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID",
-// "Get Mandate",
-// s"""Get a mandate by its ID.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// MandateJsonV600(
-// mandate_id = "mandate-id-123",
-// bank_id = "gh.29.uk",
-// account_id = "8ca8a7e4-6d02",
-// customer_id = "customer-id-123",
-// mandate_name = "ACME Corp Operating Account Authority",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "The following persons are authorised...",
-// description = "Payment authority for ACME Corp",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z",
-// created_by_user_id = "user-id-123",
-// updated_by_user_id = "user-id-123"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetMandate))
-// )
-//
-// lazy val getMandate: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "mandates" :: mandateId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (mandate, callContext) <- Connector.connector.vend.getMandateById(
-// mandateId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Mandate not found. Mandate ID: $mandateId", 404), i._2)
-// }
-// } yield {
-// (createMandateJsonV600(mandate), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateMandate,
-// implementedInApiVersion,
-// nameOf(updateMandate),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID",
-// "Update Mandate",
-// s"""Update a mandate.
-// |
-// |Authentication is Required
-// |""",
-// UpdateMandateJsonV600(
-// mandate_name = "Updated Mandate Name",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "Updated legal text...",
-// description = "Updated description",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z"
-// ),
-// MandateJsonV600(
-// mandate_id = "mandate-id-123",
-// bank_id = "gh.29.uk",
-// account_id = "8ca8a7e4-6d02",
-// customer_id = "customer-id-123",
-// mandate_name = "Updated Mandate Name",
-// mandate_reference = "MND-2026-00042",
-// legal_text = "Updated legal text...",
-// description = "Updated description",
-// status = "ACTIVE",
-// valid_from = "2026-01-01T00:00:00Z",
-// valid_to = "2027-01-01T00:00:00Z",
-// created_by_user_id = "user-id-123",
-// updated_by_user_id = "user-id-456"
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canUpdateMandate))
-// )
-//
-// lazy val updateMandate: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "mandates" :: mandateId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateMandateJsonV600]
-// }
-// validFrom <- NewStyle.function.tryons(s"$InvalidDateFormat valid_from must be in yyyy-MM-dd'T'HH:mm:ss'Z' format", 400, cc.callContext) {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(updateJson.valid_from)
-// }
-// validTo <- NewStyle.function.tryons(s"$InvalidDateFormat valid_to must be in yyyy-MM-dd'T'HH:mm:ss'Z' format", 400, cc.callContext) {
-// val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-// formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
-// formatter.setLenient(false)
-// formatter.parse(updateJson.valid_to)
-// }
-// (mandate, callContext) <- Connector.connector.vend.updateMandate(
-// mandateId,
-// updateJson.mandate_name,
-// updateJson.mandate_reference,
-// updateJson.legal_text,
-// updateJson.description,
-// updateJson.status,
-// validFrom,
-// validTo,
-// cc.userId,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not update mandate. Mandate ID: $mandateId"), i._2)
-// }
-// } yield {
-// (createMandateJsonV600(mandate), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMandate,
-// implementedInApiVersion,
-// nameOf(deleteMandate),
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID",
-// "Delete Mandate",
-// s"""Delete a mandate and all its provisions and signatory panels.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canDeleteMandate))
-// )
-//
-// lazy val deleteMandate: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "mandates" :: mandateId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- Connector.connector.vend.deleteMandate(
-// mandateId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not delete mandate. Mandate ID: $mandateId"), i._2)
-// }
-// } yield {
-// (deleted, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // ========== Mandate Provision Endpoints ==========
-//
-// staticResourceDocs += ResourceDoc(
-// createMandateProvision,
-// implementedInApiVersion,
-// nameOf(createMandateProvision),
-// "POST",
-// "/banks/BANK_ID/mandates/MANDATE_ID/provisions",
-// "Create Mandate Provision",
-// s"""Create a new provision for a mandate.
-// |
-// |A provision links the mandate's legal clauses to OBP enforcement mechanisms
-// |(Views, ABAC Rules, Challenges).
-// |
-// |**Provision types:**
-// |- SIGNATORY_RULE — Who can sign and in what combination
-// |- VIEW_ASSIGNMENT — Which view a signatory panel gets on the account
-// |- ABAC_CONDITION — Links to an ABAC rule for attribute-based conditions
-// |- RESTRICTION — Negative rule (e.g., no international payments)
-// |- NOTIFICATION — Triggers notification rather than blocking
-// |
-// |Authentication is Required
-// |""",
-// CreateMandateProvisionJsonV600(
-// provision_name = "Payments under 5000",
-// provision_description = "Any single Director may authorise payments below EUR 5,000",
-// legal_reference = "Clause 3.1(a)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 5000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 1)),
-// linked_view_id = Some("PaymentInitiator"),
-// linked_abac_rule_id = None,
-// linked_challenge_type = Some("OBP_TRANSACTION_REQUEST_CHALLENGE"),
-// is_active = true,
-// sort_order = 1
-// ),
-// MandateProvisionJsonV600(
-// provision_id = "provision-id-123",
-// mandate_id = "mandate-id-123",
-// provision_name = "Payments under 5000",
-// provision_description = "Any single Director may authorise payments below EUR 5,000",
-// legal_reference = "Clause 3.1(a)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 5000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 1)),
-// linked_view_id = "PaymentInitiator",
-// linked_abac_rule_id = "",
-// linked_challenge_type = "OBP_TRANSACTION_REQUEST_CHALLENGE",
-// is_active = true,
-// sort_order = 1
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canCreateMandateProvision))
-// )
-//
-// lazy val createMandateProvision: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "provisions" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// createJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[CreateMandateProvisionJsonV600]
-// }
-// sigReqJson <- Future {
-// import org.json4s._
-// implicit val formats: Formats = DefaultFormats
-// org.json4s.native.Serialization.write(createJson.signatory_requirements)
-// }
-// (provision, callContext) <- Connector.connector.vend.createMandateProvision(
-// mandateId,
-// createJson.provision_name,
-// createJson.provision_description,
-// createJson.legal_reference,
-// createJson.provision_type,
-// createJson.conditions,
-// sigReqJson,
-// createJson.linked_view_id.getOrElse(""),
-// createJson.linked_abac_rule_id.getOrElse(""),
-// createJson.linked_challenge_type.getOrElse(""),
-// createJson.is_active,
-// createJson.sort_order,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not create mandate provision"), i._2)
-// }
-// } yield {
-// (createMandateProvisionJsonV600(provision), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMandateProvisions,
-// implementedInApiVersion,
-// nameOf(getMandateProvisions),
-// "GET",
-// "/banks/BANK_ID/mandates/MANDATE_ID/provisions",
-// "Get Mandate Provisions",
-// s"""Get all provisions for a mandate.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// MandateProvisionsJsonV600(List(MandateProvisionJsonV600(
-// provision_id = "provision-id-123",
-// mandate_id = "mandate-id-123",
-// provision_name = "Payments under 5000",
-// provision_description = "Any single Director may authorise payments below EUR 5,000",
-// legal_reference = "Clause 3.1(a)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 5000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 1)),
-// linked_view_id = "PaymentInitiator",
-// linked_abac_rule_id = "",
-// linked_challenge_type = "OBP_TRANSACTION_REQUEST_CHALLENGE",
-// is_active = true,
-// sort_order = 1
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetMandateProvision))
-// )
-//
-// lazy val getMandateProvisions: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "provisions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (provisions, callContext) <- Connector.connector.vend.getMandateProvisionsByMandateId(
-// mandateId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not get provisions for mandate: $mandateId"), i._2)
-// }
-// } yield {
-// (createMandateProvisionsJsonV600(provisions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getMandateProvision,
-// implementedInApiVersion,
-// nameOf(getMandateProvision),
-// "GET",
-// "/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID",
-// "Get Mandate Provision",
-// s"""Get a specific provision by its ID.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// MandateProvisionJsonV600(
-// provision_id = "provision-id-123",
-// mandate_id = "mandate-id-123",
-// provision_name = "Payments under 5000",
-// provision_description = "Any single Director may authorise payments below EUR 5,000",
-// legal_reference = "Clause 3.1(a)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 5000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 1)),
-// linked_view_id = "PaymentInitiator",
-// linked_abac_rule_id = "",
-// linked_challenge_type = "OBP_TRANSACTION_REQUEST_CHALLENGE",
-// is_active = true,
-// sort_order = 1
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetMandateProvision))
-// )
-//
-// lazy val getMandateProvision: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "provisions" :: provisionId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (provision, callContext) <- Connector.connector.vend.getMandateProvisionById(
-// provisionId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Mandate provision not found. Provision ID: $provisionId", 404), i._2)
-// }
-// } yield {
-// (createMandateProvisionJsonV600(provision), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateMandateProvision,
-// implementedInApiVersion,
-// nameOf(updateMandateProvision),
-// "PUT",
-// "/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID",
-// "Update Mandate Provision",
-// s"""Update a mandate provision.
-// |
-// |Authentication is Required
-// |""",
-// UpdateMandateProvisionJsonV600(
-// provision_name = "Updated provision",
-// provision_description = "Updated description",
-// legal_reference = "Clause 3.1(b)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 50000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 2)),
-// linked_view_id = Some("PaymentInitiator"),
-// linked_abac_rule_id = None,
-// linked_challenge_type = Some("OBP_TRANSACTION_REQUEST_CHALLENGE"),
-// is_active = true,
-// sort_order = 2
-// ),
-// MandateProvisionJsonV600(
-// provision_id = "provision-id-123",
-// mandate_id = "mandate-id-123",
-// provision_name = "Updated provision",
-// provision_description = "Updated description",
-// legal_reference = "Clause 3.1(b)",
-// provision_type = "SIGNATORY_RULE",
-// conditions = """{"currency": "EUR", "amount_below": 50000.00}""",
-// signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = "panel-id-001", required_count = 2)),
-// linked_view_id = "PaymentInitiator",
-// linked_abac_rule_id = "",
-// linked_challenge_type = "OBP_TRANSACTION_REQUEST_CHALLENGE",
-// is_active = true,
-// sort_order = 2
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canUpdateMandateProvision))
-// )
-//
-// lazy val updateMandateProvision: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "provisions" :: provisionId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateMandateProvisionJsonV600]
-// }
-// sigReqJson <- Future {
-// import org.json4s._
-// implicit val formats: Formats = DefaultFormats
-// org.json4s.native.Serialization.write(updateJson.signatory_requirements)
-// }
-// (provision, callContext) <- Connector.connector.vend.updateMandateProvision(
-// provisionId,
-// updateJson.provision_name,
-// updateJson.provision_description,
-// updateJson.legal_reference,
-// updateJson.provision_type,
-// updateJson.conditions,
-// sigReqJson,
-// updateJson.linked_view_id.getOrElse(""),
-// updateJson.linked_abac_rule_id.getOrElse(""),
-// updateJson.linked_challenge_type.getOrElse(""),
-// updateJson.is_active,
-// updateJson.sort_order,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not update provision. Provision ID: $provisionId"), i._2)
-// }
-// } yield {
-// (createMandateProvisionJsonV600(provision), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteMandateProvision,
-// implementedInApiVersion,
-// nameOf(deleteMandateProvision),
-// "DELETE",
-// "/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID",
-// "Delete Mandate Provision",
-// s"""Delete a mandate provision.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canDeleteMandateProvision))
-// )
-//
-// lazy val deleteMandateProvision: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "provisions" :: provisionId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- Connector.connector.vend.deleteMandateProvision(
-// provisionId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not delete provision. Provision ID: $provisionId"), i._2)
-// }
-// } yield {
-// (deleted, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // ========== Signatory Panel Endpoints ==========
-//
-// staticResourceDocs += ResourceDoc(
-// createSignatoryPanel,
-// implementedInApiVersion,
-// nameOf(createSignatoryPanel),
-// "POST",
-// "/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels",
-// "Create Signatory Panel",
-// s"""Create a new signatory panel for a mandate.
-// |
-// |A signatory panel is a named set of authorised signatories (users) that can be
-// |referenced by mandate provisions. For example, "Panel A - Directors" and "Panel B - Finance".
-// |
-// |Provision rules then reference panels, e.g., "1 from Panel A and 1 from Panel B".
-// |
-// |Authentication is Required
-// |""",
-// CreateSignatoryPanelJsonV600(
-// panel_name = "Panel A - Directors",
-// description = "Board directors authorised to sign",
-// user_ids = List("user-id-1", "user-id-2", "user-id-3")
-// ),
-// SignatoryPanelJsonV600(
-// panel_id = "panel-id-001",
-// mandate_id = "mandate-id-123",
-// panel_name = "Panel A - Directors",
-// description = "Board directors authorised to sign",
-// user_ids = List("user-id-1", "user-id-2", "user-id-3")
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canCreateSignatoryPanel))
-// )
-//
-// lazy val createSignatoryPanel: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "signatory-panels" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// createJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[CreateSignatoryPanelJsonV600]
-// }
-// userIdsStr = createJson.user_ids.mkString(",")
-// (panel, callContext) <- Connector.connector.vend.createSignatoryPanel(
-// mandateId,
-// createJson.panel_name,
-// createJson.description,
-// userIdsStr,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not create signatory panel"), i._2)
-// }
-// } yield {
-// (createSignatoryPanelJsonV600(panel), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSignatoryPanels,
-// implementedInApiVersion,
-// nameOf(getSignatoryPanels),
-// "GET",
-// "/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels",
-// "Get Signatory Panels",
-// s"""Get all signatory panels for a mandate.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// SignatoryPanelsJsonV600(List(SignatoryPanelJsonV600(
-// panel_id = "panel-id-001",
-// mandate_id = "mandate-id-123",
-// panel_name = "Panel A - Directors",
-// description = "Board directors authorised to sign",
-// user_ids = List("user-id-1", "user-id-2", "user-id-3")
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetSignatoryPanel))
-// )
-//
-// lazy val getSignatoryPanels: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "signatory-panels" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (panels, callContext) <- Connector.connector.vend.getSignatoryPanelsByMandateId(
-// mandateId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not get signatory panels for mandate: $mandateId"), i._2)
-// }
-// } yield {
-// (createSignatoryPanelsJsonV600(panels), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getSignatoryPanel,
-// implementedInApiVersion,
-// nameOf(getSignatoryPanel),
-// "GET",
-// "/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID",
-// "Get Signatory Panel",
-// s"""Get a specific signatory panel by its ID.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// SignatoryPanelJsonV600(
-// panel_id = "panel-id-001",
-// mandate_id = "mandate-id-123",
-// panel_name = "Panel A - Directors",
-// description = "Board directors authorised to sign",
-// user_ids = List("user-id-1", "user-id-2", "user-id-3")
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canGetSignatoryPanel))
-// )
-//
-// lazy val getSignatoryPanel: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "signatory-panels" :: panelId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (panel, callContext) <- Connector.connector.vend.getSignatoryPanelById(
-// panelId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Signatory panel not found. Panel ID: $panelId", 404), i._2)
-// }
-// } yield {
-// (createSignatoryPanelJsonV600(panel), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateSignatoryPanel,
-// implementedInApiVersion,
-// nameOf(updateSignatoryPanel),
-// "PUT",
-// "/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID",
-// "Update Signatory Panel",
-// s"""Update a signatory panel.
-// |
-// |Authentication is Required
-// |""",
-// UpdateSignatoryPanelJsonV600(
-// panel_name = "Panel A - Updated Directors",
-// description = "Updated board directors",
-// user_ids = List("user-id-1", "user-id-2", "user-id-4")
-// ),
-// SignatoryPanelJsonV600(
-// panel_id = "panel-id-001",
-// mandate_id = "mandate-id-123",
-// panel_name = "Panel A - Updated Directors",
-// description = "Updated board directors",
-// user_ids = List("user-id-1", "user-id-2", "user-id-4")
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canUpdateSignatoryPanel))
-// )
-//
-// lazy val updateSignatoryPanel: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "signatory-panels" :: panelId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, cc.callContext) {
-// json.extract[UpdateSignatoryPanelJsonV600]
-// }
-// userIdsStr = updateJson.user_ids.mkString(",")
-// (panel, callContext) <- Connector.connector.vend.updateSignatoryPanel(
-// panelId,
-// updateJson.panel_name,
-// updateJson.description,
-// userIdsStr,
-// cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not update signatory panel. Panel ID: $panelId"), i._2)
-// }
-// } yield {
-// (createSignatoryPanelJsonV600(panel), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteSignatoryPanel,
-// implementedInApiVersion,
-// nameOf(deleteSignatoryPanel),
-// "DELETE",
-// "/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID",
-// "Delete Signatory Panel",
-// s"""Delete a signatory panel.
-// |
-// |Authentication is Required
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// $BankNotFound,
-// UnknownError
-// ),
-// List(apiTagMandate),
-// Some(List(canDeleteSignatoryPanel))
-// )
-//
-// lazy val deleteSignatoryPanel: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "mandates" :: mandateId :: "signatory-panels" :: panelId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- Connector.connector.vend.deleteSignatoryPanel(
-// panelId, cc.callContext
-// ) map {
-// i => (unboxFullOrFail(i._1, cc.callContext, s"Could not delete signatory panel. Panel ID: $panelId"), i._2)
-// }
-// } yield {
-// (deleted, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCounterpartyAttribute,
-// implementedInApiVersion,
-// nameOf(createCounterpartyAttribute),
-// "POST",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes",
-// "Create Counterparty Attribute",
-// s"""
-// | Create a new Counterparty Attribute for a given COUNTERPARTY_ID.
-// |
-// | The type field must be one of "STRING", "INTEGER", "DOUBLE" or "DATE_WITH_DAY".
-// | Authentication is Required
-// |
-// """.stripMargin,
-// counterpartyAttributeRequestJsonV600,
-// counterpartyAttributeResponseJsonV600,
-// List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError),
-// List(apiTagCounterpartyAttribute, apiTagApi),
-// Some(List(canCreateCounterpartyAttribute))
-// )
-//
-// lazy val createCounterpartyAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "counterparties" :: counterpartyId :: "attributes" :: Nil JsonPost json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CounterpartyAttributeRequestJsonV600 ", 400, cc.callContext) {
-// json.extract[CounterpartyAttributeRequestJsonV600]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CounterpartyAttributeType.DOUBLE}(12.1234), ${CounterpartyAttributeType.STRING}(TAX_NUMBER), ${CounterpartyAttributeType.INTEGER}(123) and ${CounterpartyAttributeType.DATE_WITH_DAY}(2012-04-23)"
-//
-// counterpartyAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// CounterpartyAttributeType.withName(postedData.attribute_type)
-// }
-//
-// (attribute, callContext) <- CounterpartyAttributeNewStyle.createOrUpdateCounterpartyAttribute(
-// counterpartyId = CounterpartyId(counterpartyId),
-// counterpartyAttributeId = None,
-// name = postedData.name,
-// attributeType = counterpartyAttributeType,
-// value = postedData.value,
-// isActive = postedData.is_active,
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory600.createCounterpartyAttributeJson(attribute), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCounterpartyAttribute,
-// implementedInApiVersion,
-// nameOf(deleteCounterpartyAttribute),
-// "DELETE",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID",
-// "Delete Counterparty Attribute",
-// s"""
-// | Delete a Counterparty Attribute specified by COUNTERPARTY_ATTRIBUTE_ID.
-// |
-// | Authentication is Required
-// |
-// """.stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagCounterpartyAttribute, apiTagApi),
-// Some(List(canDeleteCounterpartyAttribute))
-// )
-//
-// lazy val deleteCounterpartyAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "counterparties" :: counterpartyId :: "attributes" :: attributeId :: Nil JsonDelete _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (deleted, callContext) <- CounterpartyAttributeNewStyle.deleteCounterpartyAttribute(attributeId, cc.callContext)
-// } yield {
-// (Full(deleted), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCounterpartyAttributeById,
-// implementedInApiVersion,
-// nameOf(getCounterpartyAttributeById),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID",
-// "Get Counterparty Attribute By ID",
-// s"""
-// | Get a specific Counterparty Attribute by its COUNTERPARTY_ATTRIBUTE_ID.
-// |
-// | Authentication is Required
-// |
-// """.stripMargin,
-// EmptyBody,
-// counterpartyAttributeResponseJsonV600,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagCounterpartyAttribute, apiTagApi),
-// Some(List(canGetCounterpartyAttribute))
-// )
-//
-// lazy val getCounterpartyAttributeById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "counterparties" :: counterpartyId :: "attributes" :: attributeId :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attribute, callContext) <- CounterpartyAttributeNewStyle.getCounterpartyAttributeById(attributeId, cc.callContext)
-// } yield {
-// (JSONFactory600.createCounterpartyAttributeJson(attribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getAllCounterpartyAttributes,
-// implementedInApiVersion,
-// nameOf(getAllCounterpartyAttributes),
-// "GET",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes",
-// "Get All Counterparty Attributes",
-// s"""
-// | Get all attributes for the specified Counterparty.
-// |
-// | Authentication is Required
-// |
-// """.stripMargin,
-// EmptyBody,
-// counterpartyAttributesJsonV600,
-// List($AuthenticatedUserIsRequired, UnknownError),
-// List(apiTagCounterpartyAttribute, apiTagApi),
-// Some(List(canGetCounterpartyAttributes))
-// )
-//
-// lazy val getAllCounterpartyAttributes: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "counterparties" :: counterpartyId :: "attributes" :: Nil JsonGet _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// (attributes, callContext) <- CounterpartyAttributeNewStyle.getCounterpartyAttributes(CounterpartyId(counterpartyId), cc.callContext)
-// } yield {
-// (JSONFactory600.createCounterpartyAttributesJson(attributes), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateCounterpartyAttribute,
-// implementedInApiVersion,
-// nameOf(updateCounterpartyAttribute),
-// "PUT",
-// "/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID",
-// "Update Counterparty Attribute",
-// s"""
-// | Update an existing Counterparty Attribute specified by COUNTERPARTY_ATTRIBUTE_ID.
-// |
-// | Authentication is Required
-// |
-// """.stripMargin,
-// counterpartyAttributeRequestJsonV600,
-// counterpartyAttributeResponseJsonV600,
-// List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError),
-// List(apiTagCounterpartyAttribute, apiTagApi),
-// Some(List(canUpdateCounterpartyAttribute))
-// )
-//
-// lazy val updateCounterpartyAttribute: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "counterparties" :: counterpartyId :: "attributes" :: attributeId :: Nil JsonPut json -> _ => {
-// cc =>
-// implicit val ec = EndpointContext(Some(cc))
-// for {
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CounterpartyAttributeRequestJsonV600 ", 400, cc.callContext) {
-// json.extract[CounterpartyAttributeRequestJsonV600]
-// }
-// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
-// s"${CounterpartyAttributeType.DOUBLE}(12.1234), ${CounterpartyAttributeType.STRING}(TAX_NUMBER), ${CounterpartyAttributeType.INTEGER}(123) and ${CounterpartyAttributeType.DATE_WITH_DAY}(2012-04-23)"
-//
-// counterpartyAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
-// CounterpartyAttributeType.withName(postedData.attribute_type)
-// }
-// (updatedAttribute, callContext) <- CounterpartyAttributeNewStyle.createOrUpdateCounterpartyAttribute(
-// counterpartyId = CounterpartyId(counterpartyId),
-// counterpartyAttributeId = Some(attributeId),
-// name = postedData.name,
-// attributeType = counterpartyAttributeType,
-// value = postedData.value,
-// isActive = postedData.is_active,
-// callContext = cc.callContext
-// )
-// } yield {
-// (JSONFactory600.createCounterpartyAttributeJson(updatedAttribute), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// createCustomerLink,
-// implementedInApiVersion,
-// nameOf(createCustomerLink),
-// "POST",
-// "/banks/BANK_ID/customer-links",
-// "Create Customer Link",
-// s"""Link a Customer to another Customer (e.g. spouse, parent, close_associate).
-// |
-// |Authentication is Required
-// |
-// |""",
-// postCustomerLinkJsonV600,
-// customerLinkJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// CreateCustomerLinkError,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canCreateCustomerLink)))
-//
-// lazy val createCustomerLink: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-links" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerLinkJsonV600 ", 400, callContext) {
-// json.extract[PostCustomerLinkJsonV600]
-// }
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(postedData.customer_id, callContext)
-// _ <- Helper.booleanToFuture(s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to match BANK_ID(${bankId.value}) in URL", 400, callContext) {
-// customer.bankId == bankId.value
-// }
-// (_, callContext) <- NewStyle.function.getBank(BankId(postedData.other_bank_id), callContext)
-// (otherCustomer, callContext) <- NewStyle.function.getCustomerByCustomerId(postedData.other_customer_id, callContext)
-// _ <- Helper.booleanToFuture(s"Bank of the other customer specified by the OTHER_CUSTOMER_ID(${otherCustomer.bankId}) has to match OTHER_BANK_ID(${postedData.other_bank_id})", 400, callContext) {
-// otherCustomer.bankId == postedData.other_bank_id
-// }
-// (customerLink, callContext) <- NewStyle.function.createCustomerLink(bankId.value, postedData.customer_id, postedData.other_bank_id, postedData.other_customer_id, postedData.relationship_to, callContext)
-// } yield {
-// (JSONFactory600.createCustomerLinkJson(customerLink), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerLinksByCustomerId,
-// implementedInApiVersion,
-// nameOf(getCustomerLinksByCustomerId),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/customer-links",
-// "Get Customer Links by CUSTOMER_ID",
-// s"""Get Customer Links by CUSTOMER_ID.
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// customerLinksJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerLinks)))
-//
-// lazy val getCustomerLinksByCustomerId: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "customer-links" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// (customerLinks, callContext) <- NewStyle.function.getCustomerLinksByCustomerId(customerId, callContext)
-// } yield {
-// (JSONFactory600.createCustomerLinksJson(customerLinks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerLinksByBankId,
-// implementedInApiVersion,
-// nameOf(getCustomerLinksByBankId),
-// "GET",
-// "/banks/BANK_ID/customer-links",
-// "Get Customer Links at Bank",
-// s"""Get all Customer Links at a Bank.
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// customerLinksJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerLinks)))
-//
-// lazy val getCustomerLinksByBankId: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-links" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// (customerLinks, callContext) <- NewStyle.function.getCustomerLinksByBankId(bankId.value, callContext)
-// } yield {
-// (JSONFactory600.createCustomerLinksJson(customerLinks), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerLinkById,
-// implementedInApiVersion,
-// nameOf(getCustomerLinkById),
-// "GET",
-// "/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID",
-// "Get Customer Link by CUSTOMER_LINK_ID",
-// s"""Get Customer Link by CUSTOMER_LINK_ID.
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// customerLinkJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerLinkNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canGetCustomerLink)))
-//
-// lazy val getCustomerLinkById: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-links" :: customerLinkId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// (customerLink, callContext) <- NewStyle.function.getCustomerLinkById(customerLinkId, callContext)
-// } yield {
-// (JSONFactory600.createCustomerLinkJson(customerLink), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// updateCustomerLink,
-// implementedInApiVersion,
-// nameOf(updateCustomerLink),
-// "PUT",
-// "/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID",
-// "Update Customer Link",
-// s"""Update an existing Customer Link.
-// |
-// |Authentication is Required
-// |
-// |""",
-// putCustomerLinkJsonV600,
-// customerLinkJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// InvalidJsonFormat,
-// CustomerLinkNotFound,
-// UserHasMissingRoles,
-// UpdateCustomerLinkError,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canUpdateCustomerLink)))
-//
-// lazy val updateCustomerLink: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-links" :: customerLinkId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutCustomerLinkJsonV600 ", 400, callContext) {
-// json.extract[PutCustomerLinkJsonV600]
-// }
-// (customerLink, callContext) <- NewStyle.function.updateCustomerLinkById(customerLinkId, postedData.relationship_to, callContext)
-// } yield {
-// (JSONFactory600.createCustomerLinkJson(customerLink), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// staticResourceDocs += ResourceDoc(
-// deleteCustomerLink,
-// implementedInApiVersion,
-// nameOf(deleteCustomerLink),
-// "DELETE",
-// "/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID",
-// "Delete Customer Link",
-// s"""Delete a Customer Link.
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerLinkNotFound,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer),
-// Some(List(canDeleteCustomerLink)))
-//
-// lazy val deleteCustomerLink: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customer-links" :: customerLinkId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// (_, callContext) <- NewStyle.function.deleteCustomerLinkById(customerLinkId, callContext)
-// } yield {
-// (Full(true), HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-//
-// staticResourceDocs += ResourceDoc(
-// getCustomerInvestigationReport,
-// implementedInApiVersion,
-// nameOf(getCustomerInvestigationReport),
-// "GET",
-// "/banks/BANK_ID/customers/CUSTOMER_ID/investigation-report",
-// "Get Customer Investigation Report",
-// s"""Get a Customer Investigation Report for fraud detection, AML (Anti-Money Laundering), and financial crime analysis.
-// |
-// |This endpoint assembles a comprehensive data package for a customer in a single API call,
-// |designed for use by AI agents, compliance officers, and financial crime investigators.
-// |
-// |**Use Cases:**
-// |
-// |* Fraud Detection - identify suspicious transaction patterns
-// |* AML / Anti-Money Laundering - trace fund flows and flag anomalies
-// |* KYC Enhanced Due Diligence - deep-dive into customer activity
-// |* Suspicious Activity Report (SAR) preparation
-// |* Financial crime investigation and evidence gathering
-// |
-// |**Data Returned:**
-// |
-// |* Customer details (legal name, KYC status)
-// |* All accounts linked to the customer (with balances)
-// |* Transaction history for those accounts (within the specified date range)
-// |* Related customers (via customer links) — spouses, associates, business partners
-// |
-// |**Suspicious Patterns This Data Supports Detecting:**
-// |
-// |* Money flowing through intermediary companies (A to B to C patterns)
-// |* Payments inconsistent with known income or salary
-// |* Transfers to related parties (spouses, associates) shortly after large inflows
-// |* Round-tripping — money returning to origin via indirect paths
-// |* Vague or generic transaction descriptions on large amounts
-// |* Structuring — multiple transactions just below reporting thresholds
-// |* Rapid movement of funds across accounts (layering)
-// |
-// |**Query Parameters:**
-// |
-// |* from_date: Start date for transactions (ISO format, e.g. $DateWithMsExampleString). Defaults to 1 year ago.
-// |* to_date: End date for transactions (ISO format, e.g. $DateWithMsExampleString). Defaults to now.
-// |* limit: Maximum number of transactions per account (default 500).
-// |
-// |**Note:** This endpoint is only available in mapped mode (connector=mapped).
-// |For other connector configurations, use the individual endpoints to retrieve
-// |customer, account, transaction, and customer link data separately.
-// |
-// |Authentication is Required
-// |
-// |""",
-// EmptyBody,
-// investigationReportJsonV600,
-// List(
-// $AuthenticatedUserIsRequired,
-// $BankNotFound,
-// CustomerNotFoundByCustomerId,
-// InvestigationReportNotAvailable,
-// UserHasMissingRoles,
-// UnknownError
-// ),
-// List(apiTagCustomer, apiTagKyc, apiTagTransaction, apiTagAccount, apiTagFinancialCrime, apiTagAiAgent),
-// Some(List(canGetInvestigationReport)))
-//
-// lazy val getCustomerInvestigationReport: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "customers" :: customerId :: "investigation-report" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (_, _, callContext) <- SS.userBank
-// // Check connector is mapped
-// connectorName = code.api.Constant.CONNECTOR.openOrThrowException("connector not set")
-// _ <- Helper.booleanToFuture(failMsg = InvestigationReportNotAvailable, cc = callContext) {
-// connectorName == "mapped"
-// }
-// // Validate customer exists
-// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext)
-// _ <- Helper.booleanToFuture(failMsg = s"Customer bank (${customer.bankId}) does not match BANK_ID (${bankId.value})", 400, callContext) {
-// customer.bankId == bankId.value
-// }
-// // Parse query params
-// fromDateStr = ObpS.param("from_date")
-// toDateStr = ObpS.param("to_date")
-// limitStr = ObpS.param("limit")
-// fromDate = fromDateStr.flatMap(d => APIUtil.parseDate(d)).getOrElse {
-// new java.util.Date(System.currentTimeMillis() - 365L * 24 * 60 * 60 * 1000)
-// }
-// toDate = toDateStr.flatMap(d => APIUtil.parseDate(d)).getOrElse {
-// new java.util.Date()
-// }
-// limit = limitStr.flatMap(s => tryo(s.toInt)).getOrElse(500)
-// // Run Doobie queries
-// accounts <- Future {
-// code.investigation.DoobieInvestigationQueries.getAccountsForCustomer(customerId)
-// }
-// accountIds = accounts.map(_.accountId)
-// transactions <- Future {
-// code.investigation.DoobieInvestigationQueries.getTransactionsForAccounts(
-// accountIds, bankId.value,
-// new java.sql.Timestamp(fromDate.getTime),
-// new java.sql.Timestamp(toDate.getTime),
-// limit
-// )
-// }
-// customerLinks <- Future {
-// code.investigation.DoobieInvestigationQueries.getCustomerLinks(customerId)
-// }
-// customerRow = code.investigation.DoobieInvestigationQueries.CustomerRow(
-// customerId = customer.customerId,
-// legalName = customer.legalName,
-// email = customer.email,
-// mobileNumber = customer.mobileNumber,
-// kycStatus = customer.kycStatus
-// )
-// } yield {
-// (JSONFactory600.createInvestigationReportJson(
-// customerRow, bankId.value, accounts, transactions, customerLinks, fromDate, toDate
-// ), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ============================================ CHAT / MESSAGING API ENDPOINTS ============================================
-//
-// // ------ Batch A: Room CRUD ------
-//
-// // 1a. createBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// createBankChatRoom,
-// implementedInApiVersion,
-// nameOf(createBankChatRoom),
-// "POST",
-// "/banks/BANK_ID/chat-rooms",
-// "Create Bank Chat Room",
-// s"""Create a new chat room scoped to a bank.
-// |The creator is automatically added as a participant with all permissions.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatRoomJsonV600(name = "General Discussion", description = "A place to discuss general topics"),
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val createBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatRoomJsonV600", 400, callContext) {
-// json.extract[PostChatRoomJsonV600]
-// }
-// existingRoom <- Future(code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomByBankIdAndName(bankId.value, postJson.name))
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomAlreadyExists, failCode = 409, cc = callContext) {
-// existingRoom.isEmpty
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.createChatRoom(bankId.value, postJson.name, postJson.description, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot create chat room", 400)
-// }
-// _ <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(room.chatRoomId, u.userId, "", code.chat.ChatPermissions.ALL_PERMISSIONS, "")
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add creator as participant", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId)), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 1b. createSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// createSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(createSystemChatRoom),
-// "POST",
-// "/chat-rooms",
-// "Create System Chat Room",
-// s"""Create a new system-level chat room (not scoped to a bank).
-// |The creator is automatically added as a participant with all permissions.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatRoomJsonV600(name = "General Discussion", description = "A place to discuss general topics"),
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val createSystemChatRoom: OBPEndpoint = {
-// case "chat-rooms" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatRoomJsonV600", 400, callContext) {
-// json.extract[PostChatRoomJsonV600]
-// }
-// existingRoom <- Future(code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomByBankIdAndName("", postJson.name))
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomAlreadyExists, failCode = 409, cc = callContext) {
-// existingRoom.isEmpty
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.createChatRoom("", postJson.name, postJson.description, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot create chat room", 400)
-// }
-// _ <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(room.chatRoomId, u.userId, "", code.chat.ChatPermissions.ALL_PERMISSIONS, "")
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add creator as participant", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId)), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 2a. getBankChatRooms
-// staticResourceDocs += ResourceDoc(
-// getBankChatRooms,
-// implementedInApiVersion,
-// nameOf(getBankChatRooms),
-// "GET",
-// "/banks/BANK_ID/chat-rooms",
-// "Get Bank Chat Rooms",
-// s"""Get all chat rooms for the specified bank that the current user is a participant of.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankChatRooms: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// rooms <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomsByBankIdForUser(bankId.value, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get chat rooms", 400)
-// }
-// unreadCounts <- Future {
-// computeUnreadCounts(rooms, u.userId)
-// }
-// participantCounts <- Future {
-// computeParticipantCounts(rooms)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 2b. getSystemChatRooms
-// staticResourceDocs += ResourceDoc(
-// getSystemChatRooms,
-// implementedInApiVersion,
-// nameOf(getSystemChatRooms),
-// "GET",
-// "/chat-rooms",
-// "Get System Chat Rooms",
-// s"""Get all system-level chat rooms that the current user is a participant of.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemChatRooms: OBPEndpoint = {
-// case "chat-rooms" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// rooms <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomsByBankIdForUser("", u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get chat rooms", 400)
-// }
-// unreadCounts <- Future {
-// computeUnreadCounts(rooms, u.userId)
-// }
-// participantCounts <- Future {
-// computeParticipantCounts(rooms)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 3a. getBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// getBankChatRoom,
-// implementedInApiVersion,
-// nameOf(getBankChatRoom),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID",
-// "Get Bank Chat Room",
-// s"""Get a specific chat room by ID within a bank. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 3b. getSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// getSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(getSystemChatRoom),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID",
-// "Get System Chat Room",
-// s"""Get a specific system-level chat room by ID. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemChatRoom: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 4a. updateBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// updateBankChatRoom,
-// implementedInApiVersion,
-// nameOf(updateBankChatRoom),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID",
-// "Update Bank Chat Room",
-// s"""Update the name and/or description of a chat room. Requires can_update_room permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutChatRoomJsonV600(name = Some("Updated Name"), description = Some("Updated description")),
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "Updated Name",
-// description = "Updated description",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// InsufficientChatPermission,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val updateBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutChatRoomJsonV600", 400, callContext) {
-// json.extract[PutChatRoomJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_UPDATE_ROOM)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.updateChatRoom(chatRoomId, putJson.name, putJson.description)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 4b. updateSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// updateSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(updateSystemChatRoom),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID",
-// "Update System Chat Room",
-// s"""Update the name and/or description of a system-level chat room. Requires can_update_room permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutChatRoomJsonV600(name = Some("Updated Name"), description = Some("Updated description")),
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "Updated Name",
-// description = "Updated description",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// InsufficientChatPermission,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val updateSystemChatRoom: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutChatRoomJsonV600", 400, callContext) {
-// json.extract[PutChatRoomJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_UPDATE_ROOM)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.updateChatRoom(chatRoomId, putJson.name, putJson.description)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 5a. deleteBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// deleteBankChatRoom,
-// implementedInApiVersion,
-// nameOf(deleteBankChatRoom),
-// "DELETE",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID",
-// "Delete Bank Chat Room",
-// s"""Delete a chat room. Requires the CanDeleteBankChatRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canDeleteBankChatRoom))
-// )
-//
-// lazy val deleteBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteBankChatRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.deleteChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot delete chat room", 400)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 5b. deleteSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// deleteSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(deleteSystemChatRoom),
-// "DELETE",
-// "/chat-rooms/CHAT_ROOM_ID",
-// "Delete System Chat Room",
-// s"""Delete a system-level chat room. Requires the CanDeleteSystemChatRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canDeleteSystemChatRoom))
-// )
-//
-// lazy val deleteSystemChatRoom: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteSystemChatRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.deleteChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot delete chat room", 400)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 6a. archiveBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// archiveBankChatRoom,
-// implementedInApiVersion,
-// nameOf(archiveBankChatRoom),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/archive-status",
-// "Archive Bank Chat Room",
-// s"""Archive a chat room. Archived rooms cannot receive new messages or participants.
-// |Requires the CanArchiveBankChatRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = true,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canArchiveBankChatRoom))
-// )
-//
-// lazy val archiveBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "archive-status" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canArchiveBankChatRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// archivedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.archiveChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot archive chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(archivedRoom, participantCount = computeParticipantCount(archivedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 6b. archiveSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// archiveSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(archiveSystemChatRoom),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/archive-status",
-// "Archive System Chat Room",
-// s"""Archive a system-level chat room. Archived rooms cannot receive new messages or participants.
-// |Requires the CanArchiveSystemChatRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = true,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canArchiveSystemChatRoom))
-// )
-//
-// lazy val archiveSystemChatRoom: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "archive-status" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canArchiveSystemChatRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// archivedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.archiveChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot archive chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(archivedRoom, participantCount = computeParticipantCount(archivedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 6c. setBankChatRoomOpenRoom
-// staticResourceDocs += ResourceDoc(
-// setBankChatRoomOpenRoom,
-// implementedInApiVersion,
-// nameOf(setBankChatRoomOpenRoom),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/open-room",
-// "Set Chat Room All Users Are Participants",
-// s"""Set whether all authenticated users are implicit participants of this chat room.
-// |
-// |If true, all users can read and send messages without needing an explicit Participant record.
-// |
-// |Requires the CanSetBankChatRoomIsOpenRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "username",
-// created_by_provider = "provider",
-// is_open_room = true,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canSetBankChatRoomIsOpenRoom))
-// )
-//
-// lazy val setBankChatRoomOpenRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "open-room" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canSetBankChatRoomIsOpenRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// isOpenRoom = (json \ "is_open_room").extractOrElse[Boolean](false)
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.setIsOpenRoom(chatRoomId, isOpenRoom)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 6d. setSystemChatRoomOpenRoom
-// staticResourceDocs += ResourceDoc(
-// setSystemChatRoomOpenRoom,
-// implementedInApiVersion,
-// nameOf(setSystemChatRoomOpenRoom),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/open-room",
-// "Set System Chat Room All Users Are Participants",
-// s"""Set whether all authenticated users are implicit participants of this system-level chat room.
-// |
-// |If true, all users can read and send messages without needing an explicit Participant record.
-// |
-// |Requires the CanSetSystemChatRoomIsOpenRoom role.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "username",
-// created_by_provider = "provider",
-// is_open_room = true,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// UserHasMissingRoles,
-// ChatRoomNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// Some(List(canSetSystemChatRoomIsOpenRoom))
-// )
-//
-// lazy val setSystemChatRoomOpenRoom: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "open-room" :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- NewStyle.function.hasEntitlement("", u.userId, canSetSystemChatRoomIsOpenRoom, callContext)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// isOpenRoom = (json \ "is_open_room").extractOrElse[Boolean](false)
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.setIsOpenRoom(chatRoomId, isOpenRoom)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId)), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch B: Joining ------
-//
-// // 7a. joinBankChatRoom
-// staticResourceDocs += ResourceDoc(
-// joinBankChatRoom,
-// implementedInApiVersion,
-// nameOf(joinBankChatRoom),
-// "POST",
-// "/banks/BANK_ID/chat-room-participants",
-// "Join Bank Chat Room",
-// s"""Join a chat room using a joining key (passed as joining_key in the JSON body).
-// |The user is added as a participant with no special permissions.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ParticipantJsonV600(
-// participant_id = "participant-id-123",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List(),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJoiningKey,
-// ChatRoomIsArchived,
-// ChatRoomParticipantAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val joinBankChatRoom: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-room-participants" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// joiningKey = (json \ "joining_key").extractOpt[String].getOrElse("")
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomByJoiningKey(joiningKey)
-// } map {
-// x => unboxFullOrFail(x, callContext, InvalidJoiningKey, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// existingParticipant <- Future(code.chat.ChatPermissions.isParticipant(room.chatRoomId, u.userId))
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomParticipantAlreadyExists, failCode = 409, cc = callContext) {
-// existingParticipant.isEmpty
-// }
-// participant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(room.chatRoomId, u.userId, "", List.empty, "")
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot join chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(participant), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 7b. joinSystemChatRoom
-// staticResourceDocs += ResourceDoc(
-// joinSystemChatRoom,
-// implementedInApiVersion,
-// nameOf(joinSystemChatRoom),
-// "POST",
-// "/chat-room-participants",
-// "Join System Chat Room",
-// s"""Join a system-level chat room using a joining key (passed as joining_key in the JSON body).
-// |The user is added as a participant with no special permissions.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ParticipantJsonV600(
-// participant_id = "participant-id-123",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List(),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJoiningKey,
-// ChatRoomIsArchived,
-// ChatRoomParticipantAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val joinSystemChatRoom: OBPEndpoint = {
-// case "chat-room-participants" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// joiningKey = (json \ "joining_key").extractOpt[String].getOrElse("")
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoomByJoiningKey(joiningKey)
-// } map {
-// x => unboxFullOrFail(x, callContext, InvalidJoiningKey, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// existingParticipant <- Future(code.chat.ChatPermissions.isParticipant(room.chatRoomId, u.userId))
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomParticipantAlreadyExists, failCode = 409, cc = callContext) {
-// existingParticipant.isEmpty
-// }
-// participant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(room.chatRoomId, u.userId, "", List.empty, "")
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot join chat room", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(participant), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 8a. refreshBankJoiningKey
-// staticResourceDocs += ResourceDoc(
-// refreshBankJoiningKey,
-// implementedInApiVersion,
-// nameOf(refreshBankJoiningKey),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/joining-key",
-// "Refresh Bank Chat Room Joining Key",
-// s"""Refresh the joining key for a chat room. The old key becomes invalid.
-// |Requires can_refresh_joining_key permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JoiningKeyJsonV600(joining_key = "new-key-abc123"),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val refreshBankJoiningKey: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "joining-key" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_REFRESH_JOINING_KEY)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.refreshJoiningKey(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot refresh joining key", 400)
-// }
-// } yield {
-// (JoiningKeyJsonV600(joining_key = updatedRoom.joiningKey), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 8b. refreshSystemJoiningKey
-// staticResourceDocs += ResourceDoc(
-// refreshSystemJoiningKey,
-// implementedInApiVersion,
-// nameOf(refreshSystemJoiningKey),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/joining-key",
-// "Refresh System Chat Room Joining Key",
-// s"""Refresh the joining key for a system-level chat room. The old key becomes invalid.
-// |Requires can_refresh_joining_key permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// JoiningKeyJsonV600(joining_key = "new-key-abc123"),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val refreshSystemJoiningKey: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "joining-key" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_REFRESH_JOINING_KEY)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// updatedRoom <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.refreshJoiningKey(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot refresh joining key", 400)
-// }
-// } yield {
-// (JoiningKeyJsonV600(joining_key = updatedRoom.joiningKey), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch C: Participants ------
-//
-// // 9a. addBankChatRoomParticipant
-// staticResourceDocs += ResourceDoc(
-// addBankChatRoomParticipant,
-// implementedInApiVersion,
-// nameOf(addBankChatRoomParticipant),
-// "POST",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants",
-// "Add Bank Chat Room Participant",
-// s"""Add a participant to a chat room. Requires can_manage_permissions permission.
-// |Specify either user_id or consumer_id, but not both.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostParticipantJsonV600(user_id = Some("user-id-456"), consumer_id = None, permissions = Some(List("can_delete_message")), webhook_url = None),
-// ParticipantJsonV600(
-// participant_id = "participant-id-456",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-456",
-// username = "ellie.y.1.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_delete_message"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// MustSpecifyUserIdOrConsumerId,
-// ChatRoomParticipantAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val addBankChatRoomParticipant: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "participants" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostParticipantJsonV600", 400, callContext) {
-// json.extract[PostParticipantJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_MANAGE_PERMISSIONS)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// userId = postJson.user_id.getOrElse("")
-// consumerId = postJson.consumer_id.getOrElse("")
-// _ <- Helper.booleanToFuture(failMsg = MustSpecifyUserIdOrConsumerId, cc = callContext) {
-// (userId.nonEmpty || consumerId.nonEmpty) && !(userId.nonEmpty && consumerId.nonEmpty)
-// }
-// existingParticipant <- Future {
-// if (userId.nonEmpty) code.chat.ChatPermissions.isParticipant(chatRoomId, userId)
-// else code.chat.ChatPermissions.isParticipantByConsumerId(chatRoomId, consumerId)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomParticipantAlreadyExists, failCode = 409, cc = callContext) {
-// existingParticipant.isEmpty
-// }
-// participant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(
-// chatRoomId, userId, consumerId,
-// postJson.permissions.getOrElse(List.empty),
-// postJson.webhook_url.getOrElse("")
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add participant", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(participant), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 9b. addSystemChatRoomParticipant
-// staticResourceDocs += ResourceDoc(
-// addSystemChatRoomParticipant,
-// implementedInApiVersion,
-// nameOf(addSystemChatRoomParticipant),
-// "POST",
-// "/chat-rooms/CHAT_ROOM_ID/participants",
-// "Add System Chat Room Participant",
-// s"""Add a participant to a system-level chat room. Requires can_manage_permissions permission.
-// |Specify either user_id or consumer_id, but not both.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostParticipantJsonV600(user_id = Some("user-id-456"), consumer_id = None, permissions = Some(List("can_delete_message")), webhook_url = None),
-// ParticipantJsonV600(
-// participant_id = "participant-id-456",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-456",
-// username = "ellie.y.1.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_delete_message"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// MustSpecifyUserIdOrConsumerId,
-// ChatRoomParticipantAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val addSystemChatRoomParticipant: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "participants" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostParticipantJsonV600", 400, callContext) {
-// json.extract[PostParticipantJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_MANAGE_PERMISSIONS)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// userId = postJson.user_id.getOrElse("")
-// consumerId = postJson.consumer_id.getOrElse("")
-// _ <- Helper.booleanToFuture(failMsg = MustSpecifyUserIdOrConsumerId, cc = callContext) {
-// (userId.nonEmpty || consumerId.nonEmpty) && !(userId.nonEmpty && consumerId.nonEmpty)
-// }
-// existingParticipant <- Future {
-// if (userId.nonEmpty) code.chat.ChatPermissions.isParticipant(chatRoomId, userId)
-// else code.chat.ChatPermissions.isParticipantByConsumerId(chatRoomId, consumerId)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomParticipantAlreadyExists, failCode = 409, cc = callContext) {
-// existingParticipant.isEmpty
-// }
-// participant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.addParticipant(
-// chatRoomId, userId, consumerId,
-// postJson.permissions.getOrElse(List.empty),
-// postJson.webhook_url.getOrElse("")
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add participant", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(participant), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 10a. getBankChatRoomParticipants
-// staticResourceDocs += ResourceDoc(
-// getBankChatRoomParticipants,
-// implementedInApiVersion,
-// nameOf(getBankChatRoomParticipants),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants",
-// "Get Bank Chat Room Participants",
-// s"""Get all participants of a chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ParticipantsJsonV600(participants = List(ParticipantJsonV600(
-// participant_id = "participant-id-123",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_update_room", "can_delete_message"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankChatRoomParticipants: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "participants" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// participants <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipants(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participants", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantsJson(participants), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 10b. getSystemChatRoomParticipants
-// staticResourceDocs += ResourceDoc(
-// getSystemChatRoomParticipants,
-// implementedInApiVersion,
-// nameOf(getSystemChatRoomParticipants),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/participants",
-// "Get System Chat Room Participants",
-// s"""Get all participants of a system-level chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ParticipantsJsonV600(participants = List(ParticipantJsonV600(
-// participant_id = "participant-id-123",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_update_room", "can_delete_message"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemChatRoomParticipants: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "participants" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// participants <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipants(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participants", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantsJson(participants), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 11a. updateBankParticipantPermissions
-// staticResourceDocs += ResourceDoc(
-// updateBankParticipantPermissions,
-// implementedInApiVersion,
-// nameOf(updateBankParticipantPermissions),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants/USER_ID",
-// "Update Bank Chat Room Participant Permissions",
-// s"""Update the permissions of a participant. Requires can_manage_permissions permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutParticipantPermissionsJsonV600(permissions = List("can_delete_message", "can_update_room")),
-// ParticipantJsonV600(
-// participant_id = "participant-id-456",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-456",
-// username = "ellie.y.1.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_delete_message", "can_update_room"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// ChatRoomParticipantNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val updateBankParticipantPermissions: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "participants" :: targetUserId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutParticipantPermissionsJsonV600", 400, callContext) {
-// json.extract[PutParticipantPermissionsJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_MANAGE_PERMISSIONS)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomParticipantNotFound, 404)
-// }
-// updatedParticipant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.updateParticipantPermissions(chatRoomId, targetUserId, putJson.permissions)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update participant permissions", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(updatedParticipant), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 11b. updateSystemParticipantPermissions
-// staticResourceDocs += ResourceDoc(
-// updateSystemParticipantPermissions,
-// implementedInApiVersion,
-// nameOf(updateSystemParticipantPermissions),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/participants/USER_ID",
-// "Update System Chat Room Participant Permissions",
-// s"""Update the permissions of a participant in a system-level chat room. Requires can_manage_permissions permission.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutParticipantPermissionsJsonV600(permissions = List("can_delete_message", "can_update_room")),
-// ParticipantJsonV600(
-// participant_id = "participant-id-456",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-456",
-// username = "ellie.y.1.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List("can_delete_message", "can_update_room"),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// ChatRoomParticipantNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val updateSystemParticipantPermissions: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "participants" :: targetUserId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutParticipantPermissionsJsonV600", 400, callContext) {
-// json.extract[PutParticipantPermissionsJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_MANAGE_PERMISSIONS)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomParticipantNotFound, 404)
-// }
-// updatedParticipant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.updateParticipantPermissions(chatRoomId, targetUserId, putJson.permissions)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update participant permissions", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(updatedParticipant), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 12a. removeBankChatRoomParticipant
-// staticResourceDocs += ResourceDoc(
-// removeBankChatRoomParticipant,
-// implementedInApiVersion,
-// nameOf(removeBankChatRoomParticipant),
-// "DELETE",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants/USER_ID",
-// "Remove Bank Chat Room Participant",
-// s"""Remove a participant from a chat room. Requires can_remove_participant permission, or the user can remove themselves.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// ChatRoomParticipantNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val removeBankChatRoomParticipant: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "participants" :: targetUserId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// // Self-removal is allowed; otherwise need can_remove_participant
-// _ <- if (u.userId == targetUserId) {
-// Future.successful(Full(()))
-// } else {
-// Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_REMOVE_PARTICIPANT)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomParticipantNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.removeParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot remove participant", 400)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 12b. removeSystemChatRoomParticipant
-// staticResourceDocs += ResourceDoc(
-// removeSystemChatRoomParticipant,
-// implementedInApiVersion,
-// nameOf(removeSystemChatRoomParticipant),
-// "DELETE",
-// "/chat-rooms/CHAT_ROOM_ID/participants/USER_ID",
-// "Remove System Chat Room Participant",
-// s"""Remove a participant from a system-level chat room. Requires can_remove_participant permission, or the user can remove themselves.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// InsufficientChatPermission,
-// ChatRoomParticipantNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val removeSystemChatRoomParticipant: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "participants" :: targetUserId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- if (u.userId == targetUserId) {
-// Future.successful(Full(()))
-// } else {
-// Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_REMOVE_PARTICIPANT)
-// } map {
-// x => unboxFullOrFail(x, callContext, InsufficientChatPermission, 403)
-// }
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomParticipantNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.removeParticipant(chatRoomId, targetUserId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot remove participant", 400)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch D: Messages ------
-//
-// // 13a. sendBankChatMessage
-// staticResourceDocs += ResourceDoc(
-// sendBankChatMessage,
-// implementedInApiVersion,
-// nameOf(sendBankChatMessage),
-// "POST",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages",
-// "Send Bank Chat Message",
-// s"""Send a message in a chat room. The current user must be a participant and the room must not be archived.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatMessageJsonV600(content = "Hello everyone!", message_type = Some("text"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None),
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatRoomIsArchived,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val sendBankChatMessage: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatMessageJsonV600", 400, callContext) {
-// json.extract[PostChatMessageJsonV600]
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.createMessage(
-// chatRoomId,
-// u.userId,
-// "",
-// postJson.content,
-// postJson.message_type.getOrElse("text"),
-// postJson.mentioned_user_ids.getOrElse(List.empty),
-// postJson.reply_to_message_id.getOrElse(""),
-// postJson.thread_id.getOrElse("")
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot send message", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterCreate(msg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(msg, List.empty), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 13b. sendSystemChatMessage
-// staticResourceDocs += ResourceDoc(
-// sendSystemChatMessage,
-// implementedInApiVersion,
-// nameOf(sendSystemChatMessage),
-// "POST",
-// "/chat-rooms/CHAT_ROOM_ID/messages",
-// "Send System Chat Message",
-// s"""Send a message in a system-level chat room. The current user must be a participant and the room must not be archived.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatMessageJsonV600(content = "Hello everyone!", message_type = Some("text"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None),
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatRoomIsArchived,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val sendSystemChatMessage: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatMessageJsonV600", 400, callContext) {
-// json.extract[PostChatMessageJsonV600]
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.createMessage(
-// chatRoomId,
-// u.userId,
-// "",
-// postJson.content,
-// postJson.message_type.getOrElse("text"),
-// postJson.mentioned_user_ids.getOrElse(List.empty),
-// postJson.reply_to_message_id.getOrElse(""),
-// postJson.thread_id.getOrElse("")
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot send message", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterCreate(msg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(msg, List.empty), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 14a. getBankChatMessages
-// staticResourceDocs += ResourceDoc(
-// getBankChatMessages,
-// implementedInApiVersion,
-// nameOf(getBankChatMessages),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages",
-// "Get Bank Chat Messages",
-// s"""Get messages in a chat room.
-// |
-// |${getObpApiRoot}/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages?limit=50&offset=0&from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString
-// |
-// |The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List(ReactionSummaryJsonV600(emoji = "thumbsup", count = 2, user_ids = List("user-1", "user-2")))
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankChatMessages: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// limitParam = ObpS.param("limit").map(_.toInt).getOrElse(50)
-// offsetParam = ObpS.param("offset").map(_.toInt).getOrElse(0)
-// fromDate = ObpS.param("from_date").flatMap(parseObpStandardDate(_).toOption).getOrElse(theEpochTime)
-// toDate = ObpS.param("to_date").flatMap(parseObpStandardDate(_).toOption).getOrElse(APIUtil.DefaultToDate)
-// (messageRows, reactionRows) = code.chat.DoobieChatMessageQueries.getMessagesWithReactions(chatRoomId, fromDate, toDate, limitParam, offsetParam)
-// } yield {
-// (JSONFactory600.createChatMessagesJsonFromRows(messageRows, reactionRows), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 14b. getSystemChatMessages
-// staticResourceDocs += ResourceDoc(
-// getSystemChatMessages,
-// implementedInApiVersion,
-// nameOf(getSystemChatMessages),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/messages",
-// "Get System Chat Messages",
-// s"""Get messages in a system-level chat room.
-// |
-// |${getObpApiRoot}/chat-rooms/CHAT_ROOM_ID/messages?limit=50&offset=0&from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString
-// |
-// |The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List(ReactionSummaryJsonV600(emoji = "thumbsup", count = 2, user_ids = List("user-1", "user-2")))
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemChatMessages: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// limitParam = ObpS.param("limit").map(_.toInt).getOrElse(50)
-// offsetParam = ObpS.param("offset").map(_.toInt).getOrElse(0)
-// fromDate = ObpS.param("from_date").flatMap(parseObpStandardDate(_).toOption).getOrElse(theEpochTime)
-// toDate = ObpS.param("to_date").flatMap(parseObpStandardDate(_).toOption).getOrElse(APIUtil.DefaultToDate)
-// (messageRows, reactionRows) = code.chat.DoobieChatMessageQueries.getMessagesWithReactions(chatRoomId, fromDate, toDate, limitParam, offsetParam)
-// } yield {
-// (JSONFactory600.createChatMessagesJsonFromRows(messageRows, reactionRows), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 15a. getBankChatMessage
-// staticResourceDocs += ResourceDoc(
-// getBankChatMessage,
-// implementedInApiVersion,
-// nameOf(getBankChatMessage),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Get Bank Chat Message",
-// s"""Get a specific message by ID. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankChatMessage: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId).openOr(List.empty)
-// }
-// } yield {
-// (JSONFactory600.createChatMessageJson(msg, reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 15b. getSystemChatMessage
-// staticResourceDocs += ResourceDoc(
-// getSystemChatMessage,
-// implementedInApiVersion,
-// nameOf(getSystemChatMessage),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Get System Chat Message",
-// s"""Get a specific message by ID in a system-level chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hello everyone!",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemChatMessage: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId).openOr(List.empty)
-// }
-// } yield {
-// (JSONFactory600.createChatMessageJson(msg, reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 16a. editBankChatMessage
-// staticResourceDocs += ResourceDoc(
-// editBankChatMessage,
-// implementedInApiVersion,
-// nameOf(editBankChatMessage),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Edit Bank Chat Message",
-// s"""Edit a message. Only the sender can edit their own messages.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutChatMessageJsonV600(content = "Updated message content"),
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Updated message content",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// CannotEditOthersMessage,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val editBankChatMessage: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutChatMessageJsonV600", 400, callContext) {
-// json.extract[PutChatMessageJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = CannotEditOthersMessage, cc = callContext) {
-// msg.senderUserId == u.userId
-// }
-// updatedMsg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.updateMessage(chatMessageId, putJson.content)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot edit message", 400)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId).openOr(List.empty)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterUpdate(updatedMsg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(updatedMsg, reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 16b. editSystemChatMessage
-// staticResourceDocs += ResourceDoc(
-// editSystemChatMessage,
-// implementedInApiVersion,
-// nameOf(editSystemChatMessage),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Edit System Chat Message",
-// s"""Edit a message in a system-level chat room. Only the sender can edit their own messages.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PutChatMessageJsonV600(content = "Updated message content"),
-// ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Updated message content",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// CannotEditOthersMessage,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val editSystemChatMessage: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonPut json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// putJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PutChatMessageJsonV600", 400, callContext) {
-// json.extract[PutChatMessageJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// _ <- Helper.booleanToFuture(failMsg = CannotEditOthersMessage, cc = callContext) {
-// msg.senderUserId == u.userId
-// }
-// updatedMsg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.updateMessage(chatMessageId, putJson.content)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot edit message", 400)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId).openOr(List.empty)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterUpdate(updatedMsg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(updatedMsg, reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 17a. deleteBankChatMessage
-// staticResourceDocs += ResourceDoc(
-// deleteBankChatMessage,
-// implementedInApiVersion,
-// nameOf(deleteBankChatMessage),
-// "DELETE",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Delete Bank Chat Message",
-// s"""Soft-delete a message. The sender can delete their own messages, or a participant with can_delete_message permission can delete any message.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// CannotDeleteMessage,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val deleteBankChatMessage: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// _ <- if (msg.senderUserId == u.userId) {
-// Future.successful(Full(()))
-// } else {
-// Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_DELETE_MESSAGE)
-// } map {
-// x => unboxFullOrFail(x, callContext, CannotDeleteMessage, 403)
-// }
-// }
-// deletedMsg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.softDeleteMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot delete message", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterDelete(deletedMsg, u.name, u.provider, "")
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 17b. deleteSystemChatMessage
-// staticResourceDocs += ResourceDoc(
-// deleteSystemChatMessage,
-// implementedInApiVersion,
-// nameOf(deleteSystemChatMessage),
-// "DELETE",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID",
-// "Delete System Chat Message",
-// s"""Soft-delete a message in a system-level chat room. The sender can delete their own messages, or a participant with can_delete_message permission can delete any message.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// CannotDeleteMessage,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val deleteSystemChatMessage: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// _ <- if (msg.senderUserId == u.userId) {
-// Future.successful(Full(()))
-// } else {
-// Future {
-// code.chat.ChatPermissions.checkParticipantPermission(chatRoomId, u.userId, code.chat.ChatPermissions.CAN_DELETE_MESSAGE)
-// } map {
-// x => unboxFullOrFail(x, callContext, CannotDeleteMessage, 403)
-// }
-// }
-// deletedMsg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.softDeleteMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot delete message", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterDelete(deletedMsg, u.name, u.provider, "")
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch E: Threads ------
-//
-// // 18a. getBankThreadReplies
-// staticResourceDocs += ResourceDoc(
-// getBankThreadReplies,
-// implementedInApiVersion,
-// nameOf(getBankThreadReplies),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread",
-// "Get Bank Thread Replies",
-// s"""Get all replies in a message thread. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(
-// chat_message_id = "reply-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-456",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "This is a reply",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "msg-id-123",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankThreadReplies: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "thread" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// replies <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getThreadReplies(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get thread replies", 400)
-// }
-// allReactions <- Future {
-// replies.map { msg =>
-// val reactions = code.chat.ReactionTrait.reactionProvider.vend.getReactions(msg.chatMessageId).openOr(List.empty)
-// (msg.chatMessageId, reactions)
-// }.toMap
-// }
-// } yield {
-// (JSONFactory600.createChatMessagesJson(replies, allReactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 18b. getSystemThreadReplies
-// staticResourceDocs += ResourceDoc(
-// getSystemThreadReplies,
-// implementedInApiVersion,
-// nameOf(getSystemThreadReplies),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread",
-// "Get System Thread Replies",
-// s"""Get all replies in a message thread in a system-level chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(
-// chat_message_id = "reply-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-456",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "This is a reply",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "msg-id-123",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemThreadReplies: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "thread" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// replies <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getThreadReplies(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get thread replies", 400)
-// }
-// allReactions <- Future {
-// replies.map { msg =>
-// val reactions = code.chat.ReactionTrait.reactionProvider.vend.getReactions(msg.chatMessageId).openOr(List.empty)
-// (msg.chatMessageId, reactions)
-// }.toMap
-// }
-// } yield {
-// (JSONFactory600.createChatMessagesJson(replies, allReactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 19a. replyInBankThread
-// staticResourceDocs += ResourceDoc(
-// replyInBankThread,
-// implementedInApiVersion,
-// nameOf(replyInBankThread),
-// "POST",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread",
-// "Reply In Bank Thread",
-// s"""Reply to a message in a thread. The current user must be a participant and the room must not be archived.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatMessageJsonV600(content = "This is a thread reply", message_type = Some("text"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None),
-// ChatMessageJsonV600(
-// chat_message_id = "reply-id-456",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "This is a thread reply",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "msg-id-123",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatRoomIsArchived,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val replyInBankThread: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "thread" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatMessageJsonV600", 400, callContext) {
-// json.extract[PostChatMessageJsonV600]
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.createMessage(
-// chatRoomId,
-// u.userId,
-// "",
-// postJson.content,
-// postJson.message_type.getOrElse("text"),
-// postJson.mentioned_user_ids.getOrElse(List.empty),
-// postJson.reply_to_message_id.getOrElse(""),
-// chatMessageId // threadId is the parent message ID
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot send thread reply", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterCreate(msg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(msg, List.empty), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 19b. replyInSystemThread
-// staticResourceDocs += ResourceDoc(
-// replyInSystemThread,
-// implementedInApiVersion,
-// nameOf(replyInSystemThread),
-// "POST",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread",
-// "Reply In System Thread",
-// s"""Reply to a message in a thread in a system-level chat room. The current user must be a participant and the room must not be archived.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostChatMessageJsonV600(content = "This is a thread reply", message_type = Some("text"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None),
-// ChatMessageJsonV600(
-// chat_message_id = "reply-id-456",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-123",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "This is a thread reply",
-// message_type = "text",
-// mentioned_user_ids = List(),
-// reply_to_message_id = "",
-// thread_id = "msg-id-123",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatRoomIsArchived,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val replyInSystemThread: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "thread" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostChatMessageJsonV600", 400, callContext) {
-// json.extract[PostChatMessageJsonV600]
-// }
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Helper.booleanToFuture(failMsg = ChatRoomIsArchived, cc = callContext) {
-// !room.isArchived
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// msg <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.createMessage(
-// chatRoomId,
-// u.userId,
-// "",
-// postJson.content,
-// postJson.message_type.getOrElse("text"),
-// postJson.mentioned_user_ids.getOrElse(List.empty),
-// postJson.reply_to_message_id.getOrElse(""),
-// chatMessageId // threadId is the parent message ID
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot send thread reply", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterCreate(msg, u.name, u.provider, "")
-// (JSONFactory600.createChatMessageJson(msg, List.empty), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch F: Reactions ------
-//
-// // 20a. addBankReaction
-// staticResourceDocs += ResourceDoc(
-// addBankReaction,
-// implementedInApiVersion,
-// nameOf(addBankReaction),
-// "POST",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions",
-// "Add Bank Reaction",
-// s"""Add a reaction (emoji) to a message. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostReactionJsonV600(emoji = "thumbsup"),
-// ReactionJsonV600(
-// reaction_id = "reaction-id-123",
-// chat_message_id = "msg-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// emoji = "thumbsup",
-// created_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// ReactionAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val addBankReaction: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostReactionJsonV600", 400, callContext) {
-// json.extract[PostReactionJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// existingReaction <- Future(code.chat.ReactionTrait.reactionProvider.vend.getReaction(chatMessageId, u.userId, postJson.emoji))
-// _ <- Helper.booleanToFuture(failMsg = ReactionAlreadyExists, failCode = 409, cc = callContext) {
-// existingReaction.isEmpty
-// }
-// reaction <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.addReaction(chatMessageId, u.userId, postJson.emoji)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add reaction", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterReactionAdd(chatRoomId, chatMessageId, postJson.emoji, u.userId, u.name, u.provider)
-// (JSONFactory600.createReactionJson(reaction), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 20b. addSystemReaction
-// staticResourceDocs += ResourceDoc(
-// addSystemReaction,
-// implementedInApiVersion,
-// nameOf(addSystemReaction),
-// "POST",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions",
-// "Add System Reaction",
-// s"""Add a reaction (emoji) to a message in a system-level chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// PostReactionJsonV600(emoji = "thumbsup"),
-// ReactionJsonV600(
-// reaction_id = "reaction-id-123",
-// chat_message_id = "msg-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// emoji = "thumbsup",
-// created_at = new java.util.Date()
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// ReactionAlreadyExists,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val addSystemReaction: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostReactionJsonV600", 400, callContext) {
-// json.extract[PostReactionJsonV600]
-// }
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// existingReaction <- Future(code.chat.ReactionTrait.reactionProvider.vend.getReaction(chatMessageId, u.userId, postJson.emoji))
-// _ <- Helper.booleanToFuture(failMsg = ReactionAlreadyExists, failCode = 409, cc = callContext) {
-// existingReaction.isEmpty
-// }
-// reaction <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.addReaction(chatMessageId, u.userId, postJson.emoji)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add reaction", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterReactionAdd(chatRoomId, chatMessageId, postJson.emoji, u.userId, u.name, u.provider)
-// (JSONFactory600.createReactionJson(reaction), HttpCode.`201`(callContext))
-// }
-// }
-// }
-//
-// // 21a. removeBankReaction
-// staticResourceDocs += ResourceDoc(
-// removeBankReaction,
-// implementedInApiVersion,
-// nameOf(removeBankReaction),
-// "DELETE",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions/EMOJI",
-// "Remove Bank Reaction",
-// s"""Remove your own reaction from a message.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// ReactionNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val removeBankReaction: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: emoji :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// decodedEmoji = URLDecoder.decode(emoji, StandardCharsets.UTF_8.name())
-// existingReaction <- Future(code.chat.ReactionTrait.reactionProvider.vend.getReaction(chatMessageId, u.userId, decodedEmoji))
-// _ <- Helper.booleanToFuture(failMsg = ReactionNotFound, cc = callContext) {
-// existingReaction.isDefined
-// }
-// _ <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.removeReaction(chatMessageId, u.userId, decodedEmoji)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot remove reaction", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterReactionRemove(chatRoomId, chatMessageId, decodedEmoji, u.userId, u.name, u.provider)
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 21b. removeSystemReaction
-// staticResourceDocs += ResourceDoc(
-// removeSystemReaction,
-// implementedInApiVersion,
-// nameOf(removeSystemReaction),
-// "DELETE",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions/EMOJI",
-// "Remove System Reaction",
-// s"""Remove your own reaction from a message in a system-level chat room.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// ReactionNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val removeSystemReaction: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: emoji :: Nil JsonDelete _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// decodedEmoji = URLDecoder.decode(emoji, StandardCharsets.UTF_8.name())
-// existingReaction <- Future(code.chat.ReactionTrait.reactionProvider.vend.getReaction(chatMessageId, u.userId, decodedEmoji))
-// _ <- Helper.booleanToFuture(failMsg = ReactionNotFound, cc = callContext) {
-// existingReaction.isDefined
-// }
-// _ <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.removeReaction(chatMessageId, u.userId, decodedEmoji)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot remove reaction", 400)
-// }
-// } yield {
-// code.chat.ChatEventPublisher.afterReactionRemove(chatRoomId, chatMessageId, decodedEmoji, u.userId, u.name, u.provider)
-// (EmptyBody, HttpCode.`204`(callContext))
-// }
-// }
-// }
-//
-// // 22a. getBankReactions
-// staticResourceDocs += ResourceDoc(
-// getBankReactions,
-// implementedInApiVersion,
-// nameOf(getBankReactions),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions",
-// "Get Bank Reactions",
-// s"""Get all reactions for a message. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ReactionsJsonV600(reactions = List(ReactionJsonV600(
-// reaction_id = "reaction-id-123",
-// chat_message_id = "msg-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// emoji = "thumbsup",
-// created_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankReactions: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get reactions", 400)
-// }
-// } yield {
-// (JSONFactory600.createReactionsJson(reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 22b. getSystemReactions
-// staticResourceDocs += ResourceDoc(
-// getSystemReactions,
-// implementedInApiVersion,
-// nameOf(getSystemReactions),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions",
-// "Get System Reactions",
-// s"""Get all reactions for a message in a system-level chat room. The current user must be a participant.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ReactionsJsonV600(reactions = List(ReactionJsonV600(
-// reaction_id = "reaction-id-123",
-// chat_message_id = "msg-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// emoji = "thumbsup",
-// created_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// ChatMessageNotFound,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemReactions: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: chatMessageId :: "reactions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMessage(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatMessageNotFound, 404)
-// }
-// reactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactions(chatMessageId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get reactions", 400)
-// }
-// } yield {
-// (JSONFactory600.createReactionsJson(reactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch G: Typing ------
-//
-// // 23a. signalBankTyping
-// staticResourceDocs += ResourceDoc(
-// signalBankTyping,
-// implementedInApiVersion,
-// nameOf(signalBankTyping),
-// "PUT",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/typing-indicators",
-// "Signal Bank Typing",
-// s"""Signal that the current user is typing in a chat room. The typing indicator expires after 5 seconds.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val signalBankTyping: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "typing-indicators" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// val key = s"chat_typing_${chatRoomId}_${u.userId}"
-// Redis.use(code.api.JedisMethod.SET, key, Some(5), Some("1"))
-// code.chat.ChatEventPublisher.afterTyping(chatRoomId, u.userId, u.name, u.provider, true)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 23b. signalSystemTyping
-// staticResourceDocs += ResourceDoc(
-// signalSystemTyping,
-// implementedInApiVersion,
-// nameOf(signalSystemTyping),
-// "PUT",
-// "/chat-rooms/CHAT_ROOM_ID/typing-indicators",
-// "Signal System Typing",
-// s"""Signal that the current user is typing in a system-level chat room. The typing indicator expires after 5 seconds.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// EmptyBody,
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val signalSystemTyping: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "typing-indicators" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// _ <- Future {
-// val key = s"chat_typing_${chatRoomId}_${u.userId}"
-// Redis.use(code.api.JedisMethod.SET, key, Some(5), Some("1"))
-// code.chat.ChatEventPublisher.afterTyping(chatRoomId, u.userId, u.name, u.provider, true)
-// }
-// } yield {
-// (EmptyBody, HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 24a. getBankTypingUsers
-// staticResourceDocs += ResourceDoc(
-// getBankTypingUsers,
-// implementedInApiVersion,
-// nameOf(getBankTypingUsers),
-// "GET",
-// "/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/typing-indicators",
-// "Get Bank Typing Users",
-// s"""Get the list of users currently typing in a chat room.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// TypingUsersJsonV600(users = List(TypingUserJsonV600(user_id = "user-id-123", username = "robert.x.0.gh", provider = "https://github.com"))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBankTypingUsers: OBPEndpoint = {
-// case "banks" :: BankId(bankId) :: "chat-rooms" :: chatRoomId :: "typing-indicators" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// participants <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipants(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participants", 400)
-// }
-// typingUsers <- Future {
-// participants.filter(_.userId.nonEmpty).flatMap { p =>
-// val key = s"chat_typing_${chatRoomId}_${p.userId}"
-// try {
-// Redis.use(code.api.JedisMethod.GET, key) match {
-// case Some(_) =>
-// val typingUser = code.users.Users.users.vend.getUserByUserId(p.userId)
-// Some(TypingUserJsonV600(user_id = p.userId, username = typingUser.map(_.name).getOrElse(""), provider = typingUser.map(_.provider).getOrElse("")))
-// case None => None
-// }
-// } catch {
-// case _: Throwable => None
-// }
-// }
-// }
-// } yield {
-// (TypingUsersJsonV600(users = typingUsers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 24b. getSystemTypingUsers
-// staticResourceDocs += ResourceDoc(
-// getSystemTypingUsers,
-// implementedInApiVersion,
-// nameOf(getSystemTypingUsers),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/typing-indicators",
-// "Get System Typing Users",
-// s"""Get the list of users currently typing in a system-level chat room.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// TypingUsersJsonV600(users = List(TypingUserJsonV600(user_id = "user-id-123", username = "robert.x.0.gh", provider = "https://github.com"))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getSystemTypingUsers: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "typing-indicators" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// participants <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipants(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participants", 400)
-// }
-// typingUsers <- Future {
-// participants.filter(_.userId.nonEmpty).flatMap { p =>
-// val key = s"chat_typing_${chatRoomId}_${p.userId}"
-// try {
-// Redis.use(code.api.JedisMethod.GET, key) match {
-// case Some(_) =>
-// val typingUser = code.users.Users.users.vend.getUserByUserId(p.userId)
-// Some(TypingUserJsonV600(user_id = p.userId, username = typingUser.map(_.name).getOrElse(""), provider = typingUser.map(_.provider).getOrElse("")))
-// case None => None
-// }
-// } catch {
-// case _: Throwable => None
-// }
-// }
-// }
-// } yield {
-// (TypingUsersJsonV600(users = typingUsers), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // ------ Batch H: User-Level ------
-//
-// // 25. getMyChatRooms
-// staticResourceDocs += ResourceDoc(
-// getMyChatRooms,
-// implementedInApiVersion,
-// nameOf(getMyChatRooms),
-// "GET",
-// "/users/current/chat-rooms",
-// "Get My Chat Rooms",
-// s"""Get all chat rooms the current user is a participant of, across all banks and system-level rooms.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "gh.29.uk",
-// name = "General Discussion",
-// description = "A place to discuss general topics",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-123",
-// created_by_username = "robert.x.0.gh",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello everyone!"),
-// last_message_sender_username =Some("robert.x.0.gh"),
-// unread_count = Some(3),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getMyChatRooms: OBPEndpoint = {
-// case "users" :: "current" :: "chat-rooms" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// participantRecords <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipantRoomsByUserId(u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participant records", 400)
-// }
-// roomsAndCounts <- Future {
-// participantRecords.flatMap { p =>
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(p.chatRoomId).toList.map { room =>
-// val count = if (room.isOpenRoom) {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadMentionCount(p.chatRoomId, p.userId, p.lastReadAt)
-// } else {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadCount(p.chatRoomId, p.userId, p.lastReadAt)
-// }
-// (room, count.openOr(0L))
-// }
-// }
-// }
-// participantCounts <- Future {
-// computeParticipantCounts(roomsAndCounts.map(_._1))
-// }
-// } yield {
-// val rooms = roomsAndCounts.map(_._1)
-// val unreadCounts = roomsAndCounts.map { case (room, count) => room.chatRoomId -> count }.toMap
-// (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 25b. searchChatRooms
-// staticResourceDocs += ResourceDoc(
-// searchChatRooms,
-// implementedInApiVersion,
-// nameOf(searchChatRooms),
-// "POST",
-// "/chat-rooms/search",
-// "Search Chat Rooms",
-// s"""Search chat rooms the current user is a participant of, filtered by the supplied criteria.
-// |
-// |Currently supports filtering by participant set:
-// |
-// |- `with_user_ids` (array of user_id strings, required): only return rooms where the current user
-// | AND every listed user_id are participants. Pass an empty list to match all of the current user's rooms.
-// |- `exact_participants` (boolean, optional, default `false`): if `true`, the room's participant set
-// | must equal exactly `{current user} ∪ with_user_ids` with no extras. Open rooms are excluded
-// | from exact-participant searches because their participant set is implicitly "everyone".
-// |
-// |Primary use case: a client looking up an existing 1-on-1 direct-message room before creating one,
-// |by calling with `with_user_ids: []` and `exact_participants: true`.
-// |
-// |The response shape is the same as `Get My Chat Rooms`.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// ChatRoomSearchRequestJsonV600(
-// with_user_ids = List("user-id-123"),
-// exact_participants = Some(true)
-// ),
-// ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(
-// chat_room_id = "chat-room-id-123",
-// bank_id = "",
-// name = "DM with robert.x.0.gh",
-// description = "",
-// joining_key = "abc123key",
-// created_by_user_id = "user-id-456",
-// created_by_username = "alice",
-// created_by_provider = "https://github.com",
-// is_open_room = false,
-// is_archived = false,
-// last_message_at = Some(new java.util.Date()),
-// last_message_preview = Some("Hello!"),
-// last_message_sender_username =Some("alice"),
-// unread_count = Some(0),
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// InvalidJsonFormat,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val searchChatRooms: OBPEndpoint = {
-// case "chat-rooms" :: "search" :: Nil JsonPost json -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ChatRoomSearchRequestJsonV600", 400, callContext) {
-// json.extract[ChatRoomSearchRequestJsonV600]
-// }
-// rooms <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.searchChatRoomsForUserWithParticipants(
-// u.userId,
-// postJson.with_user_ids,
-// postJson.exact_participants.getOrElse(false)
-// )
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot search chat rooms", 400)
-// }
-// unreadCounts <- Future {
-// computeUnreadCounts(rooms, u.userId)
-// }
-// participantCounts <- Future {
-// computeParticipantCounts(rooms)
-// }
-// } yield {
-// (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 26. getMyUnreadCounts
-// staticResourceDocs += ResourceDoc(
-// getMyUnreadCounts,
-// implementedInApiVersion,
-// nameOf(getMyUnreadCounts),
-// "GET",
-// "/users/current/chat-rooms/unread",
-// "Get My Unread Counts",
-// s"""Get unread message counts for all chat rooms the current user is a participant of.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// UnreadCountsJsonV600(unread_counts = List(UnreadCountJsonV600(chat_room_id = "chat-room-id-123", unread_count = 5))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getMyUnreadCounts: OBPEndpoint = {
-// case "users" :: "current" :: "chat-rooms" :: "unread" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// participantRecords <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.getParticipantRoomsByUserId(u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get participant records", 400)
-// }
-// unreadCounts <- Future {
-// participantRecords.flatMap { p =>
-// val room = code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(p.chatRoomId)
-// val isOpenRoom = room.map(_.isOpenRoom).openOr(false)
-// val count = if (isOpenRoom) {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadMentionCount(p.chatRoomId, p.userId, p.lastReadAt)
-// } else {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadCount(p.chatRoomId, p.userId, p.lastReadAt)
-// }
-// count.toList.map(c => UnreadCountJsonV600(chat_room_id = p.chatRoomId, unread_count = c))
-// }
-// }
-// } yield {
-// (UnreadCountsJsonV600(unread_counts = unreadCounts), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 27. markChatRoomRead
-// staticResourceDocs += ResourceDoc(
-// markChatRoomRead,
-// implementedInApiVersion,
-// nameOf(markChatRoomRead),
-// "PUT",
-// "/users/current/chat-rooms/CHAT_ROOM_ID/read-marker",
-// "Mark Chat Room Read",
-// s"""Mark all messages in a chat room as read for the current user by updating lastReadAt to now.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ParticipantJsonV600(
-// participant_id = "participant-id-123",
-// chat_room_id = "chat-room-id-123",
-// user_id = "user-id-123",
-// username = "robert.x.0.gh",
-// provider = "https://github.com",
-// consumer_id = "",
-// consumer_name = "",
-// permissions = List(),
-// webhook_url = "",
-// joined_at = new java.util.Date(),
-// last_read_at = new java.util.Date(),
-// is_muted = false
-// ),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val markChatRoomRead: OBPEndpoint = {
-// case "users" :: "current" :: "chat-rooms" :: chatRoomId :: "read-marker" :: Nil JsonPut _ -> _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// _ <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// updatedParticipant <- Future {
-// code.chat.ParticipantTrait.participantProvider.vend.updateLastReadAt(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot mark as read", 400)
-// }
-// } yield {
-// (JSONFactory600.createParticipantJson(updatedParticipant), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 28. getMyMentions
-// staticResourceDocs += ResourceDoc(
-// getMyMentions,
-// implementedInApiVersion,
-// nameOf(getMyMentions),
-// "GET",
-// "/users/current/mentions",
-// "Get My Mentions",
-// s"""Get messages where the current user is mentioned. Supports limit and offset query parameters.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(
-// chat_message_id = "msg-id-123",
-// chat_room_id = "chat-room-id-123",
-// sender_user_id = "user-id-456",
-// sender_consumer_id = "",
-// sender_username = "robert.x.0.gh",
-// sender_provider = "https://github.com",
-// sender_consumer_name = "My Banking App",
-// content = "Hey @user-id-123, check this out!",
-// message_type = "text",
-// mentioned_user_ids = List("user-id-123"),
-// reply_to_message_id = "",
-// thread_id = "",
-// is_deleted = false,
-// created_at = new java.util.Date(),
-// updated_at = new java.util.Date(),
-// reactions = List()
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getMyMentions: OBPEndpoint = {
-// case "users" :: "current" :: "mentions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// limitParam = ObpS.param("limit").map(_.toInt).getOrElse(50)
-// offsetParam = ObpS.param("offset").map(_.toInt).getOrElse(0)
-// messages <- Future {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getMentionsForUser(u.userId, limitParam, offsetParam)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get mentions", 400)
-// }
-// allReactions <- Future {
-// messages.map { msg =>
-// val reactions = code.chat.ReactionTrait.reactionProvider.vend.getReactions(msg.chatMessageId).openOr(List.empty)
-// (msg.chatMessageId, reactions)
-// }.toMap
-// }
-// } yield {
-// (JSONFactory600.createChatMessagesJson(messages, allReactions), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// // 29. getBulkReactions
-// staticResourceDocs += ResourceDoc(
-// getBulkReactions,
-// implementedInApiVersion,
-// nameOf(getBulkReactions),
-// "GET",
-// "/chat-rooms/CHAT_ROOM_ID/messages/reactions",
-// "Get Bulk Reactions",
-// s"""Get reactions for multiple messages in a single request.
-// |
-// |Pass message IDs as a comma-separated query parameter: ?message_ids=id1,id2,id3
-// |
-// |Returns reactions grouped by message ID.
-// |
-// |Authentication is Required
-// |
-// |""".stripMargin,
-// EmptyBody,
-// BulkReactionsJsonV600(message_reactions = List(MessageReactionsJsonV600(
-// chat_message_id = "msg-id-123",
-// reactions = List(ReactionSummaryJsonV600(emoji = "thumbsup", count = 2, user_ids = List("user-1", "user-2")))
-// ))),
-// List(
-// $AuthenticatedUserIsRequired,
-// ChatRoomNotFound,
-// NotChatRoomParticipant,
-// UnknownError
-// ),
-// List(apiTagChat),
-// None
-// )
-//
-// lazy val getBulkReactions: OBPEndpoint = {
-// case "chat-rooms" :: chatRoomId :: "messages" :: "reactions" :: Nil JsonGet _ => {
-// cc => implicit val ec = EndpointContext(Some(cc))
-// for {
-// (Full(u), callContext) <- authenticatedAccess(cc)
-// room <- Future {
-// code.chat.ChatRoomTrait.chatRoomProvider.vend.getChatRoom(chatRoomId)
-// } map {
-// x => unboxFullOrFail(x, callContext, ChatRoomNotFound, 404)
-// }
-// _ <- Future {
-// code.chat.ChatPermissions.isParticipant(chatRoomId, u.userId)
-// } map {
-// x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
-// }
-// messageIds = ObpS.param("message_ids").map(_.split(",").map(_.trim).filter(_.nonEmpty).toList).getOrElse(List.empty)
-// allReactions <- Future {
-// code.chat.ReactionTrait.reactionProvider.vend.getReactionsForMessages(messageIds)
-// } map {
-// x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot get reactions", 400)
-// }
-// } yield {
-// (JSONFactory600.createBulkReactionsJson(allReactions, messageIds), HttpCode.`200`(callContext))
-// }
-// }
-// }
-//
-// /**
-// * Compute the participant count for a single chat room.
-// */
-// private def computeParticipantCount(chatRoomId: String): Long = {
-// code.chat.ParticipantTrait.participantProvider.vend
-// .getParticipants(chatRoomId)
-// .map(_.length.toLong)
-// .openOr(0L)
-// }
-//
-// /**
-// * Compute the participant count for each given room.
-// * One DB query per room — same N+1 pattern as `computeUnreadCounts`.
-// */
-// private def computeParticipantCounts(rooms: List[code.chat.ChatRoomTrait]): Map[String, Long] = {
-// rooms.map(room => room.chatRoomId -> computeParticipantCount(room.chatRoomId)).toMap
-// }
-//
-// /**
-// * Compute unread counts for a list of rooms for a given user.
-// * For open rooms, counts only mentions. For private rooms, counts all unread messages.
-// */
-// private def computeUnreadCounts(rooms: List[code.chat.ChatRoomTrait], userId: String): Map[String, Long] = {
-// rooms.flatMap { room =>
-// val participant = code.chat.ChatPermissions.isParticipant(room.chatRoomId, userId)
-// participant.toList.map { p =>
-// val count = if (room.isOpenRoom) {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadMentionCount(room.chatRoomId, userId, p.lastReadAt)
-// } else {
-// code.chat.ChatMessageTrait.chatMessageProvider.vend.getUnreadCount(room.chatRoomId, userId, p.lastReadAt)
-// }
-// room.chatRoomId -> count.openOr(0L)
-// }
-// }.toMap
-// }
-//
-// }
-//}
-//
-//
-//
-//object APIMethods600 {
-// lazy val newStyleEndpoints: List[(String, String)] = Implementations6_0_0.resourceDocs.map {
-// rd => (rd.partialFunctionName, rd.implementedInApiVersion.toString())
-// }.toList
-//
-// // Canonical cache key for product-list endpoints. Params are sorted by name (and by value within each)
-// // so that `?tag=a&tag=b` and `?tag=b&tag=a` share a cache entry. Bank is "__all__" for the system-level endpoint.
-// def productsCacheKey(bankId: String, params: List[GetProductsParam]): String = {
-// val canonical = params
-// .map(p => p.name -> p.value.sorted)
-// .sortBy(_._1)
-// .map { case (name, values) => s"$name=${values.mkString(",")}" }
-// .mkString("&")
-// s"productsV600:$bankId:$canonical"
-// }
-//}
diff --git a/obp-api/src/main/scala/code/api/v6_0_0/Http4s600.scala b/obp-api/src/main/scala/code/api/v6_0_0/Http4s600.scala
index a4bb0fe6b6..71bc720d11 100644
--- a/obp-api/src/main/scala/code/api/v6_0_0/Http4s600.scala
+++ b/obp-api/src/main/scala/code/api/v6_0_0/Http4s600.scala
@@ -127,7 +127,7 @@ object Http4s600 {
val prefixPath = Root / ApiPathZero.toString / implementedInApiVersion.toString
// Local config flag referenced by some lifted product-endpoint descriptions.
- // Mirrors the same `val` in `code.api.v2_1_0.{APIMethods210, Http4s210}`.
+ // Mirrors the same `val` in `code.api.v2_1_0.Http4s210`.
val getProductsIsPublic =
APIUtil.getPropsAsBoolValue("apiOptions.getProductsIsPublic", true)
@@ -15197,7 +15197,7 @@ object Http4s600 {
private lazy val v6ResourceDocIndex: ResourceDocMatcher.ResourceDocIndex =
ResourceDocMatcher.buildIndex(resourceDocs)
- // `lazy val`, not `val`: `OBPAPI6_0_0` and `APIMethods600` reference
+ // `lazy val`, not `val`: other objects reference
// `Http4s600.Implementations6_0_0` directly via getstatic. When either is loaded
// first (during Lift's Boot), the JVM triggers `Implementations6_0_0.`
// before `Http4s600.`. Resource-doc registrations inside Impl6.
diff --git a/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala b/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala
deleted file mode 100644
index 54c9f8b2a8..0000000000
--- a/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
-Open Bank Project - API
-Copyright (C) 2011-2019, TESOBE GmbH.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
-Email: contact@tesobe.com
-TESOBE GmbH.
-Osloer Strasse 16/17
-Berlin 13359, Germany
-
-This product includes software developed at
-TESOBE (http://www.tesobe.com/)
-
- */
-package code.api.v6_0_0
-
-
-import scala.language.reflectiveCalls
-import code.api.OBPRestHelper
-import code.api.util.VersionedOBPApis
-import code.api.v3_0_0.Http4s300
-import code.api.v3_1_0.{APIMethods310, Http4s310}
-import code.api.v4_0_0.{APIMethods400, Http4s400}
-import code.api.v5_0_0.APIMethods500
-import code.api.v5_1_0.{APIMethods510, Http4s510, OBPAPI5_1_0}
-import code.util.Helper.MdcLoggable
-import com.github.dwickern.macros.NameOf.nameOf
-import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
-
-/*
-This file defines which endpoints from all the versions are available in v6.0.0.
-All v6.0.0 endpoints have been migrated to Http4s600 — this object is retained
-only for resource-doc aggregation and the Lift dispatch registry.
- */
-object OBPAPI6_0_0 extends OBPRestHelper
- with APIMethods310
- with APIMethods400
- with APIMethods500
- with APIMethods510
- with MdcLoggable
- with VersionedOBPApis{
-
- val version : ApiVersion = ApiVersion.v6_0_0
-
- val versionStatus = ApiVersionStatus.BLEEDING_EDGE.toString
-
- // Re-export so tests that import OBPAPI6_0_0.Implementations6_0_0 still compile.
- val Implementations6_0_0 = Http4s600.Implementations6_0_0
- // Re-export so nameOf references below (in excludeEndpoints) continue to compile
- // after APIMethods510 was replaced with an empty stub.
- val Implementations5_1_0 = Http4s510.Implementations5_1_0
- // Re-export so nameOf references below (in excludeEndpoints) continue to compile
- // after APIMethods400 was replaced with an empty stub.
- val Implementations4_0_0 = Http4s400.Implementations4_0_0
- // Re-export so nameOf(Implementations3_1_0.xxx) in excludeEndpoints continues to compile
- // after APIMethods310 was replaced with an empty stub.
- val Implementations3_1_0 = Http4s310.Implementations3_1_0
- // Re-export so nameOf(Implementations3_0_0.xxx) in excludeEndpoints continues to compile
- // after APIMethods300 was replaced with an empty stub.
- val Implementations3_0_0 = Http4s300.Implementations3_0_0
-
- lazy val excludeEndpoints =
- nameOf(Implementations3_0_0.getUserByUsername) ::
- nameOf(Implementations3_1_0.getBadLoginStatus) ::
- nameOf(Implementations3_1_0.unlockUser) ::
- nameOf(Implementations4_0_0.lockUser) ::
- nameOf(Implementations4_0_0.createUserWithAccountAccess) ::
- nameOf(Implementations4_0_0.grantUserAccessToView) ::
- nameOf(Implementations4_0_0.revokeUserAccessToView) ::
- nameOf(Implementations4_0_0.revokeGrantUserAccessToViews) ::
- nameOf(Implementations4_0_0.getMyPersonalUserAttributes) ::
- nameOf(Implementations4_0_0.createMyPersonalUserAttribute) ::
- nameOf(Implementations4_0_0.updateMyPersonalUserAttribute) ::
- nameOf(Implementations5_1_0.createNonPersonalUserAttribute) ::
- nameOf(Implementations5_1_0.getNonPersonalUserAttributes) ::
- nameOf(Implementations5_1_0.deleteNonPersonalUserAttribute) ::
- Nil
-
- // All v6.0.0 endpoints live in Http4s600 — aggregate Http4s600.resourceDocs on top of v5.1.0.
- def allResourceDocs = collectResourceDocs(
- OBPAPI5_1_0.allResourceDocs,
- Http4s600.resourceDocs
- ).filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|")))
-
- // No Lift routes — all v6.0.0 endpoints are served by Http4s600.
-
- logger.info(s"version $version has been run! ${allResourceDocs.length} allResourceDocs.")
- // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here.
-}
diff --git a/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala b/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala
index c27c550700..692b459cb2 100644
--- a/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala
+++ b/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala
@@ -106,7 +106,7 @@ object Http4s700 {
* Aggregated resource docs from all API versions (v7.0.0 + v6.0.0 + v5.1.0 + ... + v1.3.0)
*
* This method implements the resource docs aggregation pattern for v7.0.0:
- * 1. Takes OBPAPI6_0_0.allResourceDocs (which already contains v6.0.0 + v5.1.0 + ... + v1.3.0)
+ * 1. Takes Http4sResourceDocAggregation.v600 (which already contains v6.0.0 + v5.1.0 + ... + v1.3.0)
* 2. Adds v7.0.0's own resourceDocs
* 3. Deduplicates by (requestUrl, requestVerb), keeping the newest version
* 4. Filters out explicitly excluded old endpoints
diff --git a/obp-api/src/main/scala/code/chat/ChatEventPublisher.scala b/obp-api/src/main/scala/code/chat/ChatEventPublisher.scala
index 03c4aa8101..658659a1e8 100644
--- a/obp-api/src/main/scala/code/chat/ChatEventPublisher.scala
+++ b/obp-api/src/main/scala/code/chat/ChatEventPublisher.scala
@@ -9,7 +9,7 @@ import org.json4s.native.Serialization.write
/**
* Publishes chat events to ChatEventBus after REST operations.
*
- * Called from APIMethods600 after createMessage, updateMessage,
+ * Called from Http4s600 after createMessage, updateMessage,
* softDeleteMessage, and typing indicator operations.
*/
object ChatEventPublisher extends MdcLoggable {
diff --git a/obp-api/src/main/scala/code/database/authorisation/Authorisation.scala b/obp-api/src/main/scala/code/database/authorisation/Authorisation.scala
deleted file mode 100644
index 9b3131b0bb..0000000000
--- a/obp-api/src/main/scala/code/database/authorisation/Authorisation.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-//package code.database.authorisation
-//
-//import net.liftweb.common.Box
-//import net.liftweb.util.SimpleInjector
-//
-//
-//object Authorisations extends SimpleInjector {
-// val authorisationProvider = new Inject(() => buildOne) {}
-// def buildOne: AuthorisationProvider = MappedAuthorisationProvider
-//}
-//
-//trait AuthorisationProvider {
-// def getAuthorizationByAuthorizationId(authorizationId: String): Box[Authorisation]
-// def getAuthorizationByAuthorizationId(paymentId: String, authorizationId: String): Box[Authorisation]
-// def getAuthorizationByPaymentId(paymentId: String): Box[List[Authorisation]]
-// def getAuthorizationByConsentId(consentId: String): Box[List[Authorisation]]
-// def createAuthorization(paymentId: String,
-// consentId: String,
-// authenticationType: String,
-// authenticationMethodId: String,
-// scaStatus: String,
-// challengeData: String
-// ): Box[Authorisation]
-// def checkAnswer(paymentId: String, authorizationId: String, challengeData: String): Box[Authorisation]
-//}
\ No newline at end of file
diff --git a/obp-api/src/main/scala/code/database/authorisation/MapperAuthorisation.scala b/obp-api/src/main/scala/code/database/authorisation/MapperAuthorisation.scala
deleted file mode 100644
index 670d658038..0000000000
--- a/obp-api/src/main/scala/code/database/authorisation/MapperAuthorisation.scala
+++ /dev/null
@@ -1,97 +0,0 @@
-//package code.database.authorisation
-//
-//import code.api.BerlinGroup.ScaStatus
-//import code.api.util.ErrorMessages
-//import code.consent.{ConsentStatus, MappedConsent}
-//import code.util.MappedUUID
-//import net.liftweb.common.{Box, Empty, Failure, Full}
-//import net.liftweb.mapper.{BaseIndex, By, CreatedUpdated, IdPK, LongKeyedMapper, LongKeyedMetaMapper, MappedString, UniqueIndex}
-//import net.liftweb.util.Helpers.tryo
-//
-//
-//class Authorisation extends LongKeyedMapper[Authorisation] with IdPK with CreatedUpdated {
-// def getSingleton = Authorisation
-// // Enum: received, psuIdentified, psuAuthenticated, scaMethodSelected, started, finalised, failed, exempted
-// object ScaStatus extends MappedString(this, 20)
-// object AuthorisationId extends MappedUUID(this)
-// object PaymentId extends MappedUUID(this)
-// object ConsentId extends MappedUUID(this)
-// // Enum: SMS_OTP, CHIP_OTP, PHOTO_OTP, PUSH_OTP
-// object AuthenticationType extends MappedString(this, 10)
-// object AuthenticationMethodId extends MappedString(this, 35)
-// object ChallengeData extends MappedString(this, 1024)
-//
-// def scaStatus: String = ScaStatus.get
-// def authorisationId: String = AuthorisationId.get
-// def paymentId: String = PaymentId.get
-// def consentId: String = ConsentId.get
-// def authenticationType: String = AuthenticationType.get
-// def authenticationMethodId: String = AuthenticationMethodId.get
-// def challengeData: String = ChallengeData.get
-//}
-//
-//object Authorisation extends Authorisation with LongKeyedMetaMapper[Authorisation] {
-// override def dbIndexes: List[BaseIndex[Authorisation]] = UniqueIndex(AuthorisationId) :: super.dbIndexes
-//}
-//
-//object MappedAuthorisationProvider extends AuthorisationProvider {
-// override def getAuthorizationByAuthorizationId(paymentId: String, authorizationId: String): Box[Authorisation] = {
-// val result: Box[Authorisation] = Authorisation.find(
-// By(Authorisation.PaymentId, paymentId),
-// By(Authorisation.AuthorisationId, authorizationId)
-// )
-// result
-// }
-// override def getAuthorizationByAuthorizationId(authorizationId: String): Box[Authorisation] = {
-// val result: Box[Authorisation] = Authorisation.find(
-// By(Authorisation.AuthorisationId, authorizationId)
-// )
-// result
-// }
-//
-// override def getAuthorizationByPaymentId(paymentId: String): Box[List[Authorisation]] = {
-// tryo(Authorisation.findAll(By(Authorisation.PaymentId, paymentId)))
-// }
-// override def getAuthorizationByConsentId(consentId: String): Box[List[Authorisation]] = {
-// tryo(Authorisation.findAll(By(Authorisation.ConsentId, consentId)))
-// }
-//
-// def createAuthorization(paymentId: String,
-// consentId: String,
-// authenticationType: String,
-// authenticationMethodId: String,
-// scaStatus: String,
-// challengeData: String
-// ): Box[Authorisation] = tryo {
-// Authorisation
-// .create
-// .PaymentId(paymentId)
-// .ConsentId(consentId)
-// .AuthenticationType(authenticationType)
-// .AuthenticationMethodId(authenticationMethodId)
-// .ChallengeData(challengeData)
-// .ScaStatus(scaStatus).saveMe()
-// }
-//
-// def checkAnswer(paymentId: String, authorizationId: String, challengeData: String): Box[Authorisation] =
-// getAuthorizationByAuthorizationId(paymentId: String, authorizationId: String) match {
-// case Full(authorisation) =>
-// authorisation.scaStatus match {
-// case value if value == ScaStatus.received.toString =>
-// val status = if (authorisation.challengeData == challengeData) ScaStatus.finalised.toString else ScaStatus.failed.toString
-// tryo(authorisation.ScaStatus(status).saveMe())
-// case _ => //make sure, only `received` can be processed, all others are invalid .
-// Failure(s"${ErrorMessages.InvalidAuthorisationStatus}.It should be `received`, but now it is `${authorisation.scaStatus}`")
-// }
-// case Empty =>
-// Empty ?~! s"${ErrorMessages.AuthorisationNotFound} Current PAYMENT_ID($paymentId) and AUTHORISATION_ID ($authorizationId),"
-// case Failure(msg, _, _) =>
-// Failure(msg)
-// case _ =>
-// Failure(ErrorMessages.UnknownError)
-// }
-//}
-//
-//
-//
-//
diff --git a/obp-api/src/main/scala/code/obp/grpc/ObpGrpcServer.scala b/obp-api/src/main/scala/code/obp/grpc/ObpGrpcServer.scala
index e5bf4aa98a..5332de2029 100644
--- a/obp-api/src/main/scala/code/obp/grpc/ObpGrpcServer.scala
+++ b/obp-api/src/main/scala/code/obp/grpc/ObpGrpcServer.scala
@@ -6,7 +6,7 @@ import scala.language.reflectiveCalls
import code.api.util.newstyle.ViewNewStyle
import code.api.util.{APIUtil, CallContext, NewStyle}
import code.api.v3_0_0.{CoreTransactionsJsonV300, ModeratedTransactionCoreWithAttributes}
-import code.api.v4_0_0.{BankJson400, BanksJson400, JSONFactory400, OBPAPI4_0_0}
+import code.api.v4_0_0.{BankJson400, BanksJson400, JSONFactory400}
import code.obp.grpc.api.BanksJson400Grpc.{BankJson400Grpc, BankRoutingJsonV121Grpc}
import code.obp.grpc.api._
import code.util.Helper
@@ -198,7 +198,7 @@ class ObpGrpcServer(executionContext: ExecutionContext, port: Int = ObpGrpcServe
// } yield {
// val (privateViewsUserCanAccessAtOneBank, privateAccountAccess) = Views.views.vend.privateViewsUserCanAccessAtBank(user, bankId)
// val availablePrivateAccounts = bank.privateAccounts(privateAccountAccess)
- // val jValue = OBPAPI4_0_0.Implementations2_0_0.processAccounts(privateViewsUserCanAccessAtOneBank, availablePrivateAccounts)
+ // val jValue = Http4s200.Implementations2_0_0.processAccounts(privateViewsUserCanAccessAtOneBank, availablePrivateAccounts)
// val jArray = JArray(
// jValue.asInstanceOf[JArray].arr.map(it => {
// val bankIdJObject: JObject = "bankId" -> (it \ "bank_id")
diff --git a/obp-api/src/main/scala/code/opentok/OpenTokUtil.scala b/obp-api/src/main/scala/code/opentok/OpenTokUtil.scala
deleted file mode 100644
index fba74bb527..0000000000
--- a/obp-api/src/main/scala/code/opentok/OpenTokUtil.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-//package code.opentok
-//
-//import code.api.util.APIUtil
-//import com.opentok._
-//import com.opentok.exception.OpenTokException
-//
-//object OpenTokUtil {
-// private var session: Session = null
-//
-// def createOpenTok: OpenTok = {
-// // Set the following constants with the API key and API secret
-// // that you receive when you sign up to use the OpenTok API:
-// val apiKey: Int = APIUtil.getPropsValue("meeting.tokbox_api_key", "0000").toInt
-// val apiSecret: String = APIUtil.getPropsValue("meeting.tokbox_api_secret", "YOUR API SECRET")
-// val opentok: OpenTok = new OpenTok(apiKey, apiSecret)
-// return opentok
-// }
-//
-// @throws[OpenTokException]
-// def getSession: Session = {
-// if (session == null) {
-// // A session that uses the OpenTok Media Router:
-// session = createOpenTok.createSession(new SessionProperties.Builder().mediaMode(MediaMode.ROUTED).build)
-// }
-// return session
-// }
-//
-// @throws[OpenTokException]
-// def generateTokenForModerator(expireTimeInMinutes: Int): String = {
-// // Generate a token. Use the Role MODERATOR. Expire time is defined by parameter expireTimeInMinutes.
-// val token: String = session.generateToken(new TokenOptions.Builder().role(Role.MODERATOR).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
-// ("name=Simon").build)
-// return token
-// }
-//
-// @throws[OpenTokException]
-// def generateTokenForPublisher(expireTimeInMinutes: Int): String = {
-// // Generate a token. Use the Role PUBLISHER. Expire time is defined by parameter expireTimeInMinutes.
-// val token: String = session.generateToken(new TokenOptions.Builder().role(Role.PUBLISHER).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
-// ("name=Simon").build)
-// return token
-// }
-//}
-//
-//class OpenTokUtil() // Empty constructor
-// extends Exception {
-//}
\ No newline at end of file
diff --git a/obp-api/src/main/scala/code/yearlycustomercharges/MappedYearlyChargeProvider.scala b/obp-api/src/main/scala/code/yearlycustomercharges/MappedYearlyChargeProvider.scala
deleted file mode 100644
index 592d9997d2..0000000000
--- a/obp-api/src/main/scala/code/yearlycustomercharges/MappedYearlyChargeProvider.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-//package code.yearlycustomercharges
-//
-//import code.util.UUIDString
-//import com.openbankproject.commons.model.{BankId, CustomerId}
-//import net.liftweb.common.Box
-//import net.liftweb.mapper._
-//
-//
-//
-//object MappedYearlyChargeProvider extends YearlyChargeProvider {
-//
-//// override protected def getYearlyChargeFromProvider(thingId: YearlyChargeId): Option[YearlyCharge] =
-//// MappedYearlyCharge.find(By(MappedYearlyCharge.thingId_, thingId.value))
-//
-// override protected def getYearlyChargesFromProvider(bankId: BankId, customerId: CustomerId, year: Int): Option[List[YearlyCharge]] = {
-// Some(MappedYearlyCharge.findAll(By(MappedYearlyCharge.bankId_, bankId.value), By(MappedYearlyCharge.customerId_, customerId.value)))
-// }
-//}
-//
-//class MappedYearlyCharge extends YearlyCharge with LongKeyedMapper[MappedYearlyCharge] with IdPK {
-//
-// override def getSingleton = MappedYearlyCharge
-//
-// object bankId_ extends UUIDString(this)
-// object customerId_ extends UUIDString(this)
-//
-// object year_ extends MappedInt(this)
-//
-//
-//
-// //override def yearlyChargeId: YearlyChargeId = YearlyChargeId(id.get)
-// override def year: Int = year_.get
-//
-//
-// // override def getSingleton = MappedYearlyCustomerCharge
-// //
-// // WIP
-// // object mCustomerNumber extends MappedString(this,123)
-// //
-// // object mYear extends MappedInt(this)
-// //
-// // object mCategoryId extends UUIDString(this)
-// // object mForcastIndictor extends MappedString(this,123)
-// // object mTypeId extends MappedString(this,123)
-// // object mNatureId extends UUIDString(this)
-// //
-// //
-// // object mCharge_Currency extends MappedString(this,3)
-// // object mCharge_Amount extends MappedString(this,32)
-// //
-// // object mUpdateDate extends MappedDateTime(this)
-// //
-// //
-// // //override def bankId: String = mBankId.get
-// // override def customerId: String = mCustomerId.get // id.toString
-// // override def customerNumber: String = mCustomerNumber.get
-// // override def year: Integer = mYear.get
-// //
-// // override def categoryId: String = mCategoryId.get
-// // override def forcastIndictor: String = mForcastIndictor.get
-// // override def typeId: String = mTypeId.get
-// // override def natureId : String = mNatureId.get
-// //
-// // override def charge: AmountOfMoney = AmountOfMoney(mCharge_Currency.get, mCharge_Amount.get)
-// // override def updateDate : Date = mUpdateDate.get
-//
-//
-//
-//
-//}
-//
-//
-//object MappedYearlyCharge extends MappedYearlyCharge with LongKeyedMetaMapper[MappedYearlyCharge] {
-// override def dbIndexes = UniqueIndex(bankId_, customerId_, year_) :: Index(bankId_) :: super.dbIndexes
-//}
-//
diff --git a/obp-api/src/main/scala/code/yearlycustomercharges/YearlyCharge.scala b/obp-api/src/main/scala/code/yearlycustomercharges/YearlyCharge.scala
deleted file mode 100644
index 54a817ee88..0000000000
--- a/obp-api/src/main/scala/code/yearlycustomercharges/YearlyCharge.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-//package code.yearlycustomercharges
-//
-//import code.api.util.APIUtil
-//import com.openbankproject.commons.model.{BankId, CustomerId}
-//import net.liftweb.common.Logger
-//import net.liftweb.util.SimpleInjector
-//
-//object YearlyCharge extends SimpleInjector {
-//
-// val yearlyChargeProvider = new Inject(() => buildOne) {}
-//
-//
-// // This determines the provider we use
-// def buildOne: YearlyChargeProvider =
-// APIUtil.getPropsValue("provider.thing").openOr("mapped") match {
-// case "mapped" => MappedYearlyChargeProvider
-// case _ => MappedYearlyChargeProvider
-// }
-//
-//}
-//
-//case class YearlyChargeId(value : String)
-//
-//// WIP
-//trait YearlyCharge {
-// def year : Int
-//
-// // def customerNumber : String
-// //
-// //
-// // def categoryId : String
-// // def forcastIndictor : String
-// // def typeId : String
-// // def natureId : String
-// // def charge : AmountOfMoney
-// // def updateDate : Date
-//
-//
-//
-//}
-//
-//
-//
-//
-//trait YearlyChargeProvider {
-//
-// private val logger = Logger(classOf[YearlyChargeProvider])
-//
-//
-// /*
-// Common logic for returning or changing Things
-// Datasource implementation details are in Thing provider
-// */
-// final def getYearlyCharges(bankId : BankId, customerId: CustomerId, year: Int) : Option[List[YearlyCharge]] = {
-// getYearlyChargesFromProvider(bankId, customerId, year) match {
-// case Some(things) => {
-//
-// val certainThings = for {
-// thing <- things // if filter etc. if need be
-// } yield thing
-// Option(certainThings)
-// }
-// case None => None
-// }
-// }
-//
-//
-// protected def getYearlyChargesFromProvider(bank : BankId, customerId: CustomerId, year: Int) : Option[List[YearlyCharge]]
-//
-//}
-//
diff --git a/obp-api/src/test/resources/frozen_type_meta_data b/obp-api/src/test/resources/frozen_type_meta_data
index a15d8f1900..6ada1da3a6 100644
Binary files a/obp-api/src/test/resources/frozen_type_meta_data and b/obp-api/src/test/resources/frozen_type_meta_data differ
diff --git a/obp-api/src/test/resources/frozen_type_meta_data.txt b/obp-api/src/test/resources/frozen_type_meta_data.txt
index d7bddd02ce..28e3174b65 100644
--- a/obp-api/src/test/resources/frozen_type_meta_data.txt
+++ b/obp-api/src/test/resources/frozen_type_meta_data.txt
@@ -309,6 +309,7 @@ endpoint v4.0.0 getAccountByAccountRouting
endpoint v4.0.0 getAccountsByAccountRoutingRegex
endpoint v4.0.0 getAccountsMinimalByCustomerId
endpoint v4.0.0 getAllAuthenticationTypeValidations
+endpoint v4.0.0 getAllAuthenticationTypeValidationsPublic
endpoint v4.0.0 getAllBankLevelDynamicMessageDocs
endpoint v4.0.0 getAllBankLevelDynamicResourceDocs
endpoint v4.0.0 getAllBankLevelEndpointMappings
@@ -317,6 +318,7 @@ endpoint v4.0.0 getAllDynamicMessageDocs
endpoint v4.0.0 getAllDynamicResourceDocs
endpoint v4.0.0 getAllEndpointMappings
endpoint v4.0.0 getAllJsonSchemaValidations
+endpoint v4.0.0 getAllJsonSchemaValidationsPublic
endpoint v4.0.0 getApiCollectionEndpoints
endpoint v4.0.0 getApiCollectionsForUser
endpoint v4.0.0 getAtm
@@ -511,7 +513,6 @@ field code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.SeverJWK use String
field code.api.util.APIUtil.BooleanBody value Boolean
field code.api.util.APIUtil.EndpointInfo name String
field code.api.util.APIUtil.EndpointInfo version String
-field code.api.util.APIUtil.JArrayBody value org.json4s.JArray
field code.api.v1_2_1.APIInfoJSON connector String
field code.api.v1_2_1.APIInfoJSON git_commit String
field code.api.v1_2_1.APIInfoJSON hosted_by code.api.v1_2_1.HostedBy
diff --git a/obp-api/src/test/scala/code/api/DirectLoginTest.scala b/obp-api/src/test/scala/code/api/DirectLoginTest.scala
index 0dbf077bf0..37264fa886 100644
--- a/obp-api/src/test/scala/code/api/DirectLoginTest.scala
+++ b/obp-api/src/test/scala/code/api/DirectLoginTest.scala
@@ -4,8 +4,8 @@ import org.json4s._
import code.api.Constant.localIdentityProvider
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages._
-import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v2_0_0.Http4s200.Implementations2_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.api.v3_0_0.UserJsonV300
import code.consumer.Consumers
import code.loginattempts.LoginAttempt
diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerFactoryUnitTest.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerFactoryUnitTest.scala
index afddf34751..014f4a83a7 100644
--- a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerFactoryUnitTest.scala
+++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerFactoryUnitTest.scala
@@ -3,17 +3,10 @@ package code.api.ResourceDocs1_4_0
import org.json4s._
import code.api.util.APIUtil.ResourceDoc
import code.api.v1_4_0.V140ServerSetup
-import code.api.v2_1_0.OBPAPI2_1_0
-import code.api.v2_2_0.OBPAPI2_2_0
-import code.api.v3_0_0.OBPAPI3_0_0
-import code.api.v3_1_0.OBPAPI3_1_0
-import code.api.v4_0_0.OBPAPI4_0_0
-import code.api.v5_0_0.OBPAPI5_0_0
-import code.api.v5_1_0.OBPAPI5_1_0
-import code.api.v6_0_0.OBPAPI6_0_0
import code.util.Helper.MdcLoggable
import scala.collection.mutable.ArrayBuffer
+import code.api.util.http4s.Http4sResourceDocAggregation
// Test case classes for JSON escaping tests
case class TestWithQuotes(name: String, description: String)
@@ -86,14 +79,14 @@ class SwaggerFactoryUnitTest extends V140ServerSetup with MdcLoggable {
) {
scenario("Test all the case classes") {
val resourceDocList: ArrayBuffer[ResourceDoc] = ArrayBuffer.empty
- OBPAPI6_0_0.allResourceDocs ++
- OBPAPI5_1_0.allResourceDocs ++
- OBPAPI5_0_0.allResourceDocs ++
- OBPAPI4_0_0.allResourceDocs ++
- OBPAPI3_1_0.allResourceDocs ++
- OBPAPI3_0_0.allResourceDocs ++
- OBPAPI2_2_0.allResourceDocs ++
- OBPAPI2_1_0.allResourceDocs
+ Http4sResourceDocAggregation.v600 ++
+ Http4sResourceDocAggregation.v510 ++
+ Http4sResourceDocAggregation.v500 ++
+ Http4sResourceDocAggregation.v400 ++
+ Http4sResourceDocAggregation.v310 ++
+ Http4sResourceDocAggregation.v300 ++
+ Http4sResourceDocAggregation.v220 ++
+ Http4sResourceDocAggregation.v210
// Translate every entity(JSON Case Class) in a list to appropriate swagger format
val listOfExampleRequestBodyDefinition =
diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerPathOrderAndArrayBodyTest.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerPathOrderAndArrayBodyTest.scala
index c436e6b162..94031a65ed 100644
--- a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerPathOrderAndArrayBodyTest.scala
+++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/SwaggerPathOrderAndArrayBodyTest.scala
@@ -2,9 +2,9 @@ package code.api.ResourceDocs1_4_0
import code.api.util.APIUtil
import code.api.v1_4_0.JSONFactory1_4_0
-import code.api.v4_0_0.OBPAPI4_0_0
import com.openbankproject.commons.util.ApiVersion
import org.scalatest.{FlatSpec, Matchers}
+import code.api.util.http4s.Http4sResourceDocAggregation
/**
* Two claims the Scala 2.13 migration made about generated documentation, neither of which any
@@ -29,7 +29,7 @@ class SwaggerPathOrderAndArrayBodyTest extends FlatSpec with Matchers {
/** Real docs rather than synthetic ones: the ordering only matters for what actually ships. */
private lazy val swagger: SwaggerJSONFactory.SwaggerResourceDoc = {
val docs = JSONFactory1_4_0
- .createResourceDocsJson(OBPAPI4_0_0.allResourceDocs.toList, isVersion4OrHigher = true, None)
+ .createResourceDocsJson(Http4sResourceDocAggregation.v400.toList, isVersion4OrHigher = true, None)
.resource_docs
SwaggerJSONFactory.createSwaggerResourceDoc(docs, ApiVersion.v4_0_0)
}
diff --git a/obp-api/src/test/scala/code/api/util/JavaWebSignatureTest.scala b/obp-api/src/test/scala/code/api/util/JavaWebSignatureTest.scala
index 7eadd0a5c8..5dc6033afc 100644
--- a/obp-api/src/test/scala/code/api/util/JavaWebSignatureTest.scala
+++ b/obp-api/src/test/scala/code/api/util/JavaWebSignatureTest.scala
@@ -5,7 +5,7 @@ import java.time.{ZoneOffset, ZonedDateTime}
import code.api.util.APIUtil.OAuth._
import code.api.util.JwsUtil.{getPem, signRequest, verifyJws}
import code.api.util.X509.validate
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.V400ServerSetup
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.common.Full
diff --git a/obp-api/src/test/scala/code/api/util/http4s/ResourceDocAggregationCoverageTest.scala b/obp-api/src/test/scala/code/api/util/http4s/ResourceDocAggregationCoverageTest.scala
new file mode 100644
index 0000000000..9805e372f3
--- /dev/null
+++ b/obp-api/src/test/scala/code/api/util/http4s/ResourceDocAggregationCoverageTest.scala
@@ -0,0 +1,60 @@
+package code.api.util.http4s
+
+import code.setup.ServerSetup
+
+import scala.reflect.runtime.{universe => ru}
+
+/**
+ * Guards the one thing about `Http4sResourceDocAggregation.allVersions` that a compiler
+ * cannot: that it lists every version whose cumulative catalog the object defines.
+ *
+ * `allVersions` is what `FrozenClassUtil` enumerates, having replaced a classpath scan for
+ * `VersionedOBPApis` implementors. A scan could not be forgotten; a hand-written list can.
+ * Adding v8.0.0 means adding `lazy val v800` to the chain AND an `allVersions` entry, and
+ * omitting the second is silent: the frozen-contract scenarios compare against a persisted
+ * fixture that has no v8.0.0 key either, so all five keep passing while the new version's
+ * endpoint set and example-class structures go unguarded.
+ *
+ * So: every `vNNN` catalog the object declares must appear in `allVersions`.
+ */
+class ResourceDocAggregationCoverageTest extends ServerSetup {
+
+ /** `v121`, `v600`, … — the per-version catalogs, found reflectively so a new one counts. */
+ private val declaredCatalogs: Set[String] = {
+ val mirror = ru.runtimeMirror(getClass.getClassLoader)
+ mirror
+ .classSymbol(Http4sResourceDocAggregation.getClass)
+ .toType
+ .members
+ .filter(_.isTerm)
+ .map(_.name.decodedName.toString.trim)
+ .filter(_.matches("^v\\d{3}$"))
+ .toSet
+ }
+
+ // The catalog vals are named v121/v510/...; take the digits so the mapping does not
+ // depend on how ApiVersion happens to render separators.
+ private val listedVersions: List[String] =
+ Http4sResourceDocAggregation.allVersions.map(c => "v" + c.version.dottedApiVersion.filter(_.isDigit))
+
+ feature("Http4sResourceDocAggregation.allVersions covers the catalogs it defines") {
+
+ scenario("every per-version catalog declared on the object is listed in allVersions") {
+ // Guards the reflection itself, so an empty result can never pass vacuously.
+ declaredCatalogs should not be empty
+ (declaredCatalogs -- listedVersions.toSet) shouldBe empty
+ }
+
+ scenario("no version is listed twice") {
+ listedVersions.distinct.size should equal(listedVersions.size)
+ }
+
+ scenario("versions are ordered oldest first, as the cumulative chain is") {
+ val versions = Http4sResourceDocAggregation.allVersions.map(_.version.dottedApiVersion)
+ versions should equal(versions.sortBy { v =>
+ val p = v.split('.').map(_.toInt)
+ (p(0), p(1), p(2))
+ })
+ }
+ }
+}
diff --git a/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala b/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala
index c8072481a9..85e2316c6b 100644
--- a/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala
+++ b/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala
@@ -7,8 +7,6 @@ import code.api.util.APIUtil.ResourceDoc
import code.api.util.{APIUtil, ExampleValue}
import code.api.util.CustomJsonFormats
import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocJson
-import code.api.v3_0_0.OBPAPI3_0_0
-import code.api.v1_2_1.OBPAPI1_2_1
import org.json4s.Extraction.decompose
import org.json4s._
import com.openbankproject.commons.util.JsonAliases._
@@ -16,6 +14,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.networknt.schema.{JsonSchemaFactory, SpecVersion}
import scala.collection.mutable;
+import code.api.util.http4s.Http4sResourceDocAggregation
case class OneClass(
string : String = "String",
@@ -117,19 +116,19 @@ class JSONFactory1_4_0Test extends code.setup.ServerSetup {
}
scenario("createResourceDocJson should work well, no exception is good enough") {
- val resourceDoc: ResourceDoc = OBPAPI3_0_0.allResourceDocs(5)
+ val resourceDoc: ResourceDoc = Http4sResourceDocAggregation.v300(5)
val result: ResourceDocJson = JSONFactory1_4_0.createLocalisedResourceDocJson(resourceDoc,false, None,
includeTechnology = false, urlParameters, "JSON request body fields:", "JSON response body fields:")
}
scenario("createResourceDocsJson should work well, no exception is good enough") {
- val resourceDoc: mutable.Seq[ResourceDoc] = OBPAPI3_0_0.allResourceDocs
+ val resourceDoc: mutable.Seq[ResourceDoc] = Http4sResourceDocAggregation.v300
val result = JSONFactory1_4_0.createResourceDocsJson(resourceDoc.toList, false, None)
}
scenario("Technology field should be None unless includeTechnology=true") {
// All versions are now on http4s — use any http4s doc.
- val http4sDoc: ResourceDoc = OBPAPI1_2_1.allResourceDocs.head
+ val http4sDoc: ResourceDoc = Http4sResourceDocAggregation.v121.head
val json1 = JSONFactory1_4_0.createLocalisedResourceDocJson(http4sDoc, false, None, includeTechnology = false, urlParameters, "JSON request body fields:", "JSON response body fields:")
json1.implemented_by.technology shouldBe None
@@ -152,7 +151,7 @@ class JSONFactory1_4_0Test extends code.setup.ServerSetup {
}
scenario("validate all the resourceDocs json schema, no exception is good enough") {
- val resourceDocsRaw= OBPAPI3_0_0.allResourceDocs
+ val resourceDocsRaw= Http4sResourceDocAggregation.v300
val resourceDocs = JSONFactory1_4_0.createResourceDocsJson(resourceDocsRaw.toList,false, None)
val mapper = new ObjectMapper()
val schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)
diff --git a/obp-api/src/test/scala/code/api/v2_1_0/CreateTransactionTypeTest.scala b/obp-api/src/test/scala/code/api/v2_1_0/CreateTransactionTypeTest.scala
index 3b9b9057c7..4162789bb8 100644
--- a/obp-api/src/test/scala/code/api/v2_1_0/CreateTransactionTypeTest.scala
+++ b/obp-api/src/test/scala/code/api/v2_1_0/CreateTransactionTypeTest.scala
@@ -5,8 +5,8 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanCreateTransactionType
import code.api.util.{APIUtil, ApiRole, ErrorMessages}
import code.api.v2_0_0.{TransactionTypeJsonV200, TransactionTypesJsonV200}
-import code.api.v2_2_0.OBPAPI2_2_0.Implementations2_0_0
-import code.api.v2_1_0.OBPAPI2_1_0.Implementations2_1_0
+import code.api.v2_0_0.Http4s200.Implementations2_0_0
+import code.api.v2_1_0.Http4s210.Implementations2_1_0
import code.setup.DefaultUsers
import code.transaction_types.MappedTransactionType
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v2_2_0/API2_2_0Test.scala b/obp-api/src/test/scala/code/api/v2_2_0/API2_2_0Test.scala
index 55ece37748..d9309e49b9 100644
--- a/obp-api/src/test/scala/code/api/v2_2_0/API2_2_0Test.scala
+++ b/obp-api/src/test/scala/code/api/v2_2_0/API2_2_0Test.scala
@@ -38,7 +38,7 @@ import code.setup.{APIResponse, DefaultUsers}
import com.openbankproject.commons.model.CreateViewJson
import net.liftweb.util.Helpers._
import org.scalatest._
-import code.api.v2_2_0.OBPAPI2_2_0.Implementations2_2_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
import com.github.dwickern.macros.NameOf.nameOf
import scala.util.Random._
diff --git a/obp-api/src/test/scala/code/api/v2_2_0/ExchangeRateTest.scala b/obp-api/src/test/scala/code/api/v2_2_0/ExchangeRateTest.scala
index 2b98968678..82364555ab 100644
--- a/obp-api/src/test/scala/code/api/v2_2_0/ExchangeRateTest.scala
+++ b/obp-api/src/test/scala/code/api/v2_2_0/ExchangeRateTest.scala
@@ -10,6 +10,7 @@ import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.scalatest.Tag
+import code.api.v2_2_0.Http4s220
class ExchangeRateTest extends V220ServerSetup with DefaultUsers {
@@ -21,7 +22,7 @@ class ExchangeRateTest extends V220ServerSetup with DefaultUsers {
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v2_2_0.toString)
- object ApiEndpoint1 extends Tag(nameOf(OBPAPI2_2_0.Implementations2_2_0.getCurrentFxRate))
+ object ApiEndpoint1 extends Tag(nameOf(Http4s220.Implementations2_2_0.getCurrentFxRate))
override def beforeAll(): Unit = {
super.beforeAll()
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/AccountTest.scala
index d7d7594062..24f3b5146f 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/AccountTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanUseAccountFirehoseAtAnyBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{AccountFirehoseNotAllowedOnThisInstance, UserHasMissingRoles}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/BranchesTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/BranchesTest.scala
index d060cff17f..a17d3d7938 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/BranchesTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/BranchesTest.scala
@@ -4,7 +4,6 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanDeleteBranchAtAnyBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.OBPQueryParam
-import code.api.v3_1_0.OBPAPI3_1_0
import code.bankconnectors.Connector
import code.branches.Branches.Branch
import code.branches.{Branches, BranchesProvider}
@@ -17,6 +16,8 @@ import org.scalatest.Tag
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.duration.DurationInt
+import code.api.v3_0_0.Http4s300
+import code.api.v3_1_0.Http4s310
/*
Note This does not test retrieval from a backend.
@@ -327,7 +328,7 @@ class BranchesTest extends V300ServerSetup with DefaultUsers {
override def afterEach(): Unit = super.afterEach()
object VersionOfApi extends Tag(ApiVersion.v3_0_0.toString)
- object ApiEndpoint extends Tag(nameOf(OBPAPI3_0_0.Implementations3_0_0.getBranches))
+ object ApiEndpoint extends Tag(nameOf(Http4s300.Implementations3_0_0.getBranches))
feature("getBranches -- /banks/BANK_ID/branches -- V300") {
@@ -407,7 +408,7 @@ class BranchesTest extends V300ServerSetup with DefaultUsers {
// But, because the delete branch endpoint unitest need get all branches endpoint, to check whether given branch is deleted
// So the delete branch endpoint unit test put at here.
object VersionOfApi_3_1_0 extends Tag(ApiVersion.v3_1_0.toString)
- object ApiEndpoint_delete_branch extends Tag(nameOf(OBPAPI3_1_0.Implementations3_1_0.deleteBranch))
+ object ApiEndpoint_delete_branch extends Tag(nameOf(Http4s310.Implementations3_1_0.deleteBranch))
scenario("We try to delete bank branche", VersionOfApi_3_1_0, ApiEndpoint_delete_branch) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteBranchAtAnyBank.toString())
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/CounterpartyTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/CounterpartyTest.scala
index 1dc35fe80b..0d33548437 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/CounterpartyTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/CounterpartyTest.scala
@@ -2,7 +2,7 @@ package code.api.v3_0_0
import code.api.Constant._
import com.openbankproject.commons.util.ApiVersion
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import com.github.dwickern.macros.NameOf.nameOf
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala
index f9548adbeb..688bdf62fa 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetEntitlementRequestsAtAnyBank}
import code.api.util.ErrorMessages._
import code.api.util.{ApiRole}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/FirehoseTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/FirehoseTest.scala
index 45e6b1b361..a4489c6d1a 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/FirehoseTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/FirehoseTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.{CanUseAccountFirehose, CanUseAccountFirehoseAtAnyBank}
import code.api.util.ErrorMessages.AccountFirehoseNotAllowedOnThisInstance
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.entitlement.Entitlement
import code.setup.PropsReset
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/GetAdapterInfoTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/GetAdapterInfoTest.scala
index c6d0f06686..a25ca838f4 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/GetAdapterInfoTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/GetAdapterInfoTest.scala
@@ -27,7 +27,7 @@ package code.api.v3_0_0
import code.api.util.ApiRole.canGetAdapterInfoAtOneBank
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.api.util.APIUtil.OAuth._
import code.entitlement.Entitlement
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/TransactionsTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/TransactionsTest.scala
index 487c22e051..33039485e3 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/TransactionsTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/TransactionsTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanUseAccountFirehoseAtAnyBank
import code.api.util.ErrorMessages.{AccountFirehoseNotAllowedOnThisInstance, UserHasMissingRoles}
import code.api.util.{APIUtil, ErrorMessages}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import com.github.dwickern.macros.NameOf.nameOf
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/UserTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/UserTest.scala
index 4ead1c5f1a..08df5249f4 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/UserTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/UserTest.scala
@@ -7,7 +7,7 @@ import code.api.util.{ApiRole, ErrorMessages}
import code.api.util.ApiRole.CanGetAnyUser
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.api.v2_0_0.JSONFactory200.UsersJsonV200
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/ViewsTests.scala b/obp-api/src/test/scala/code/api/v3_0_0/ViewsTests.scala
index 4a434407a2..6d21dc5797 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/ViewsTests.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/ViewsTests.scala
@@ -35,7 +35,7 @@ import code.api.util.APIUtil.OAuth._
import com.openbankproject.commons.util.ApiVersion
import code.api.v1_2_1.{APIInfoJSON, PermissionJSON, PermissionsJSON}
import code.api.v2_2_0.{ViewJSONV220, ViewsJSONV220}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{CreateViewJson, UpdateViewJSON}
diff --git a/obp-api/src/test/scala/code/api/v3_0_0/WarehouseTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/WarehouseTest.scala
index 286b27ad3f..92b30c96bd 100644
--- a/obp-api/src/test/scala/code/api/v3_0_0/WarehouseTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_0_0/WarehouseTest.scala
@@ -8,7 +8,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanSearchWarehouse
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.setup.{APIResponse, DefaultUsers}
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/AccountAttributeTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/AccountAttributeTest.scala
index 0840caa931..b4d4b5831e 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/AccountAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/AccountAttributeTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
index b32dd1ebb1..34fe5697e5 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
@@ -12,9 +12,9 @@ import code.api.util.ApiRole
import code.api.v2_0_0.BasicAccountJSON
import code.api.v2_2_0.CreateAccountJSONV220
import code.api.v3_0_0.{CoreAccountsJsonV300, ModeratedCoreAccountJsonV300}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
-import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
+import code.api.v2_0_0.Http4s200.Implementations2_0_0
import code.entitlement.Entitlement
import code.model.dataAccess.BankAccountRouting
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/CardAttributeTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/CardAttributeTest.scala
index 76d1f4e992..2184559ea3 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/CardAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/CardAttributeTest.scala
@@ -7,13 +7,14 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createPhysicalCardJsonV
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanCreateCustomer
import code.api.util.ApiRole
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.json4s.native.Serialization.write
import org.scalatest.Tag
+import code.api.util.http4s.Http4sResourceDocAggregation
class CardAttributeTest extends V310ServerSetup with DefaultUsers {
@@ -93,7 +94,7 @@ class CardAttributeTest extends V310ServerSetup with DefaultUsers {
Then(s"We call the create card attribute")
val requestForCreateCardAttribute = (v3_1_0_Request / "management"/ "banks" / testBankId1.value / "cards" /cardId /"attribute").POST <@(user1)
- val properCreateCardAttributeJson = OBPAPI3_1_0.allResourceDocs.filter(_.partialFunctionName==nameOf(Implementations3_1_0.createCardAttribute)).head.exampleRequestBody.asInstanceOf[CardAttributeJson]
+ val properCreateCardAttributeJson = Http4sResourceDocAggregation.v310.filter(_.partialFunctionName==nameOf(Implementations3_1_0.createCardAttribute)).head.exampleRequestBody.asInstanceOf[CardAttributeJson]
val responseForCreateCardAttribute = makePostRequest(requestForCreateCardAttribute, write(properCreateCardAttributeJson))
responseForCreateCardAttribute.code should be (201)
responseForCreateCardAttribute.body.toString contains (properCreateCardAttributeJson.name) should be (true)
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/CardTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/CardTest.scala
index cdf972e6ea..9dd96df041 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/CardTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/CardTest.scala
@@ -8,7 +8,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{createPhysicalCardJson
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanCreateCustomer
import code.api.util.ApiRole
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ConsentTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ConsentTest.scala
index 177f7af24e..dcf2782b66 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ConsentTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ConsentTest.scala
@@ -33,8 +33,8 @@ import code.api.util.{APIUtil, Consent}
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v3_0_0.{APIMethods300, UserJsonV300}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_0_0.{Http4s300, UserJsonV300}
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
@@ -66,7 +66,7 @@ class ConsentTest extends V310ServerSetup {
object ApiEndpoint2 extends Tag(nameOf(Implementations3_1_0.answerConsentChallenge))
object VersionOfApi2 extends Tag(ApiVersion.v3_0_0.toString)
- object ApiEndpoint3 extends Tag(nameOf(APIMethods300.Implementations3_0_0.getUserByUserId))
+ object ApiEndpoint3 extends Tag(nameOf(Http4s300.Implementations3_0_0.getUserByUserId))
val validHeaderConsumerKey = List((RequestHeader.`Consumer-Key`, user1.map(_._1.key).getOrElse("SHOULD_NOT_HAPPEN")))
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ConsumerTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ConsumerTest.scala
index 940130599e..44804c243f 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ConsumerTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ConsumerTest.scala
@@ -31,7 +31,7 @@ import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
import code.api.v2_1_0.ConsumersJson
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/CustomerAddressTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/CustomerAddressTest.scala
index 313b5a16d8..2d6ebfe9c4 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/CustomerAddressTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/CustomerAddressTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/CustomerTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/CustomerTest.scala
index 44e2e20f38..7c932e5b71 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/CustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/CustomerTest.scala
@@ -34,7 +34,7 @@ import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
import code.api.v3_0_0.ModeratedCoreAccountsJsonV300
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/FundsAvailableTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/FundsAvailableTest.scala
index af09867e38..5a249460f1 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/FundsAvailableTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/FundsAvailableTest.scala
@@ -32,7 +32,7 @@ import code.api.util.ApiRole.canCheckFundsAvailable
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
import code.api.v1_2_1.{CreateViewJsonV121, ViewJSONV121}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/GetAdapterInfoTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/GetAdapterInfoTest.scala
index ce12e579c3..35a3470c21 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/GetAdapterInfoTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/GetAdapterInfoTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateAccountAttributeAtOneBank, canGetAdapterInfo}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.setup.{APIResponse, DefaultUsers}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/GetMessageDocsSwaggerTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/GetMessageDocsSwaggerTest.scala
index 647ce0e78f..9a5a24eaa6 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/GetMessageDocsSwaggerTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/GetMessageDocsSwaggerTest.scala
@@ -26,7 +26,7 @@ TESOBE (http://www.tesobe.com/)
package code.api.v3_1_0
import code.api.v2_2_0.JSONFactory220.MessageDocsJson
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/MeetingsTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/MeetingsTest.scala
index 1a68ded29d..ea5b770bba 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/MeetingsTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/MeetingsTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{InvalidJsonFormat, AuthenticatedUserIsRequired}
import code.api.v2_0_0.CreateMeetingJson
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
index f220f10980..8f80bf9bc5 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import code.methodrouting.{MethodRoutingCommons, MethodRoutingParam}
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ObpApiLoopbackTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ObpApiLoopbackTest.scala
index 3dd0e9a6f1..7cb28ab83c 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ObpApiLoopbackTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ObpApiLoopbackTest.scala
@@ -26,7 +26,7 @@ TESOBE (http://www.tesobe.com/)
package code.api.v3_1_0
import code.api.util.ErrorMessages.{MandatoryPropertyIsNotSet, NotImplemented}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ProductAttributeTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ProductAttributeTest.scala
index 42373946b0..f882af74b8 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ProductAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ProductAttributeTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.enums.ProductAttributeType
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ProductCollectionTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ProductCollectionTest.scala
index c282876f22..c1481bef60 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ProductCollectionTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ProductCollectionTest.scala
@@ -30,7 +30,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateProduct, CanMaintainProductCollection}
import com.openbankproject.commons.util.ApiVersion
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/ProductTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/ProductTest.scala
index 634ec1b980..e119449c68 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/ProductTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/ProductTest.scala
@@ -33,7 +33,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.Extraction
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/RateLimitTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/RateLimitTest.scala
index 20a4241e9b..b594d296ff 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/RateLimitTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/RateLimitTest.scala
@@ -35,7 +35,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.{ApiRole, RateLimitingUtil}
import code.api.util.ApiRole.{CanReadCallLimits, CanUpdateRateLimits}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.consumer.Consumers
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/RefreshObpDateTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/RefreshObpDateTest.scala
index a5073570df..04245d620d 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/RefreshObpDateTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/RefreshObpDateTest.scala
@@ -30,7 +30,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanRefreshUser
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/SystemViewsTests.scala b/obp-api/src/test/scala/code/api/v3_1_0/SystemViewsTests.scala
index 1bece325e8..3b34c4b21f 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/SystemViewsTests.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/SystemViewsTests.scala
@@ -37,7 +37,7 @@ import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequ
import code.api.util.APIUtil
import code.api.v1_2_1.APIInfoJSON
import code.api.v3_0_0.ViewJsonV300
-import code.api.v3_1_0.APIMethods310.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import code.setup.APIResponse
import code.views.MapperViews
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/TaxResidenceTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/TaxResidenceTest.scala
index b7d1a2580f..8bf7404d45 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/TaxResidenceTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/TaxResidenceTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/TransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/TransactionRequestTest.scala
index 8435accdfb..e1b9265d66 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/TransactionRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/TransactionRequestTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil
import code.api.util.ErrorMessages._
import code.api.v2_1_0.TransactionRequestWithChargeJSONs210
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AccountId, BankId}
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/TransactionTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/TransactionTest.scala
index 724b3d98e3..5de7f2ba77 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/TransactionTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/TransactionTest.scala
@@ -38,9 +38,9 @@ import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140
import code.api.v2_1_0.TransactionRequestWithChargeJSONs210
import code.api.v2_2_0.CounterpartyWithMetadataJson
import code.api.v3_0_0.{NewModeratedCoreAccountJsonV300, TransactionJsonV300}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations2_2_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.AmountOfMoneyJsonV121
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextTest.scala
index c7f710c407..c547c7d09f 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextUpdateTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextUpdateTest.scala
index b624e64ae2..d2c6c84d1c 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextUpdateTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/UserAuthContextUpdateTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateCustomer, CanGetUserAuthContext, CanGetUserCustomerLink}
import code.api.util.ApiRole
import code.api.v2_0_0.UserCustomerLinksJson
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.consumer.Consumers
import code.context.UserAuthContextUpdateProvider
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/WebUiPropsTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/WebUiPropsTest.scala
index ba825fd978..5f7a31ac31 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/WebUiPropsTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/WebUiPropsTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import code.webuiprops.WebUiPropsCommons
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/WebhooksTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/WebhooksTest.scala
index aa3bcf99cd..6299df417f 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/WebhooksTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/WebhooksTest.scala
@@ -33,7 +33,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.util.ApiTrigger
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AccountAccessTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AccountAccessTest.scala
index e1784ab9fc..e9c620b644 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AccountAccessTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AccountAccessTest.scala
@@ -10,7 +10,7 @@ import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.AuthenticatedUserIsRequired
import code.api.v3_0_0.ViewJsonV300
import code.api.v3_1_0.CreateAccountResponseJsonV310
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.AmountOfMoneyJsonV121
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AccountBalanceTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AccountBalanceTest.scala
index d11231ead3..0dca44106d 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AccountBalanceTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AccountBalanceTest.scala
@@ -2,7 +2,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.CannotFindAccountAccess
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala
index c50d8ad507..e929f05254 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala
@@ -6,7 +6,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.AuthenticatedUserIsRequired
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AccountTest.scala
index 16f6ceb2a5..bf35a00c51 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AccountTest.scala
@@ -9,7 +9,7 @@ import code.api.util.ErrorMessages.{BankAccountNotFoundByAccountRouting, UserHas
import code.api.util.{APIUtil, ApiRole}
import code.api.v2_0_0.BasicAccountJSON
import code.api.v3_1_0.{CreateAccountResponseJsonV310, CustomerJsonV310, PostCustomerNumberJsonV310, PostPutProductJsonV310, ProductJsonV310}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.enums.AccountRoutingScheme
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionEndpointTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionEndpointTest.scala
index 26d40aa469..e5ebda8f2b 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionEndpointTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionEndpointTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.berlin.group.v1_3.Http4sBGv13Alias
import code.api.util.APIUtil.OAuth._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionTest.scala
index e889dc5718..c345688176 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ApiCollectionTest.scala
@@ -30,7 +30,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ErrorMessages.{ApiCollectionEndpointNotFound, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AtmsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AtmsTest.scala
index cd7fa76343..eebe1506f9 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AtmsTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AtmsTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.{canUpdateAtm, canUpdateAtmAtAnyBank}
import code.api.util.ErrorMessages.{$AuthenticatedUserIsRequired, UserHasMissingRoles}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDefinitionTransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDefinitionTransactionRequestTest.scala
index 4baaf792c5..891ea92f65 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDefinitionTransactionRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDefinitionTransactionRequestTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationAttributeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationAttributeTest.scala
index dafb3d4cbe..bade92bcf1 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationAttributeTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCardTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCardTest.scala
index 3f719174a5..cbff51c40b 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCardTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCardTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCustomerTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCustomerTest.scala
index 245dd10742..ce55ef7983 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationCustomerTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationProductTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationProductTest.scala
index 396d364fca..6621070a62 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationProductTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationProductTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationTransactionTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationTransactionTest.scala
index 0efcfad9b6..f314f65cae 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationTransactionTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AttributeDocumentationTransactionTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationPublicPropTrueTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationPublicPropTrueTest.scala
new file mode 100644
index 0000000000..5b99126172
--- /dev/null
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationPublicPropTrueTest.scala
@@ -0,0 +1,83 @@
+package code.api.v4_0_0
+
+import code.api.util.APIUtil.OAuth._
+import code.api.util.ErrorMessages._
+import code.api.util.ApiRole
+import code.entitlement.Entitlement
+import code.setup.APIResponse
+import com.openbankproject.commons.model.ErrorMessage
+import com.openbankproject.commons.util.ApiVersion
+import com.openbankproject.commons.util.json
+import org.json4s.JArray
+import org.json4s.JString
+import org.scalatest.Tag
+
+// Boots its own JVM with read_authentication_type_validation_requires_role forced true, via
+// OBP_READ_AUTHENTICATION_TYPE_VALIDATION_REQUIRES_ROLE (see run_tests_parallel.sh and the CI job
+// that runs this class in isolation). Same rationale as JsonSchemaValidationPublicPropTrueTest:
+// the prop's effect is baked into Http4s400's ResourceDoc error list at object-initialization
+// time, so it needs its own process to observe the true branch.
+class AuthenticationTypeValidationPublicPropTrueTest extends V400ServerSetup {
+
+ object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString)
+ object PropGatedPublicEndpoint extends Tag("PropGatedPublicEndpoint")
+
+ private val mockOperationId = "MOCK_OPERATION_ID"
+
+ private val allowedDirectLogin =
+ """
+ |["DirectLogin"]
+ |""".stripMargin
+
+ private def grantEntitlement(role: ApiRole) =
+ Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, role.toString)
+
+ private def addOneAuthenticationTypeValidation(allowedAuthTypes: String, operationId: String): APIResponse = {
+ grantEntitlement(ApiRole.canCreateAuthenticationTypeValidation)
+ val request = (v4_0_0_Request / "management" / "authentication-type-validations" / operationId).POST <@ user1
+ val response = makePostRequest(request, allowedAuthTypes)
+ response.code should equal(201)
+ response
+ }
+
+ feature(s"test GET /endpoints/authentication-type-validations version $VersionOfApi - read_authentication_type_validation_requires_role=true") {
+ scenario("Anonymous access is rejected when the prop requires authentication", PropGatedPublicEndpoint, VersionOfApi) {
+ When("We make an anonymous request to the public endpoint")
+ val request = (v4_0_0_Request / "endpoints" / "authentication-type-validations").GET
+ val response = makeGetRequest(request)
+ Then("We should get a 401")
+ response.code should equal(401)
+ response.body.extract[ErrorMessage].message should equal(AuthenticatedUserIsRequired)
+ }
+
+ // user2 deliberately: the setup below grants roles to user1, so asserting the 403 as user1
+ // could not tell "the role is required" apart from "some role user1 already holds suffices".
+ scenario("Authenticated access without the role is rejected when the prop requires the role", PropGatedPublicEndpoint, VersionOfApi) {
+ addOneAuthenticationTypeValidation(allowedDirectLogin, mockOperationId)
+
+ When("We make an authenticated request as a user holding no entitlement")
+ val request = (v4_0_0_Request / "endpoints" / "authentication-type-validations").GET <@ user2
+ val response = makeGetRequest(request)
+ Then("We should get a 403 naming the missing role")
+ response.code should equal(403)
+ response.body.extract[ErrorMessage].message should include(
+ ApiRole.canGetAuthenticationTypeValidation.toString)
+ }
+
+ scenario("Authenticated access with the role succeeds when the prop requires the role", PropGatedPublicEndpoint, VersionOfApi) {
+ addOneAuthenticationTypeValidation(allowedDirectLogin, mockOperationId)
+ grantEntitlement(ApiRole.canGetAuthenticationTypeValidation)
+
+ When("We make an authenticated request as a user holding the role")
+ val request = (v4_0_0_Request / "endpoints" / "authentication-type-validations").GET <@ user1
+ val response = makeGetRequest(request)
+ Then("We should get a 200")
+ response.code should equal(200)
+ val authTypeValidations = response.body \ "authentication_types_validations"
+ authTypeValidations shouldBe a[JArray]
+ val authTypeValidation = authTypeValidations(0)
+ authTypeValidation \ "operation_id" should equal(JString(mockOperationId))
+ authTypeValidation \ "allowed_authentication_types" should equal(json.parse(allowedDirectLogin))
+ }
+ }
+}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationTest.scala
index 5af94309ca..0e802a6a3d 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/AuthenticationTypeValidationTest.scala
@@ -5,8 +5,8 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations2_2_0
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/BankAttributeTests.scala b/obp-api/src/test/scala/code/api/v4_0_0/BankAttributeTests.scala
index f74fea4715..1e7b4d4ec8 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/BankAttributeTests.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/BankAttributeTests.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateBankAttribute, CanDeleteBankAttribute, CanGetBankAttribute, CanUpdateBankAttribute}
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/BankTests.scala b/obp-api/src/test/scala/code/api/v4_0_0/BankTests.scala
index ce5f907bae..9154557f5d 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/BankTests.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/BankTests.scala
@@ -8,7 +8,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanCreateBank
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.api.util.{ApiRole, ErrorMessages, NewStyle}
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.{APIResponse, DefaultUsers}
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ConnectorMethodTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ConnectorMethodTest.scala
index 4fad2e1353..4ee5e9d8ed 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ConnectorMethodTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ConnectorMethodTest.scala
@@ -31,7 +31,7 @@ import code.api.util.ApiRole._
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.{ConnectorMethodAlreadyExists, UserHasMissingRoles}
import code.api.util.{ApiRole, CallContext}
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.bankconnectors.InternalConnector
import code.connectormethod.{ConnectorMethodProvider, JsonConnectorMethod}
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ConsentTests.scala b/obp-api/src/test/scala/code/api/v4_0_0/ConsentTests.scala
index 4c38fb7dee..fd15d40c48 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ConsentTests.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ConsentTests.scala
@@ -2,7 +2,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CorrelatedUserInfoTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CorrelatedUserInfoTest.scala
index 2c5facd69a..76d93107d3 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/CorrelatedUserInfoTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/CorrelatedUserInfoTest.scala
@@ -3,7 +3,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetCorrelatedUsersInfo, CanGetCorrelatedUsersInfoAtAnyBank}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala
index 64d1c0c22c..17d307261f 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala
@@ -6,7 +6,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.views.Views
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CustomerAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CustomerAttributesTest.scala
index 92a1f37bae..7c0927f901 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/CustomerAttributesTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/CustomerAttributesTest.scala
@@ -9,7 +9,7 @@ import code.api.util.ExampleValue.{customerAttributeValueExample,customerAttribu
import code.api.v3_0_0.CustomerAttributeResponseJsonV300
import code.api.v3_1_0.CustomerWithAttributesJsonV310
import com.openbankproject.commons.model.ListResult
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CustomerMessageTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CustomerMessageTest.scala
index ec76608432..fe0b6f0f75 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/CustomerMessageTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/CustomerMessageTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v3_1_0.CustomerJsonV310
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CustomerTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CustomerTest.scala
index 13be809dbc..1b63a20868 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/CustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/CustomerTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v3_0_0.CustomerJSONsV300
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v3_1_0.{CustomerJsonV310, PostCustomerNumberJsonV310}
import code.customer.CustomerX
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DeleteAccountCascadeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DeleteAccountCascadeTest.scala
index c154c263f5..3cc9d7e58f 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DeleteAccountCascadeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DeleteAccountCascadeTest.scala
@@ -9,7 +9,7 @@ import code.api.util.ApiRole
import code.api.util.ApiRole.CanDeleteAccountCascade
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v3_1_0.CreateAccountResponseJsonV310
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DeleteBankCascadeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DeleteBankCascadeTest.scala
index a77ce4c3e9..d45e7489e9 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DeleteBankCascadeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DeleteBankCascadeTest.scala
@@ -11,7 +11,7 @@ import code.api.util.ApiRole.{CanDeleteBankCascade, canGetCustomersMinimalAtAllB
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.util.{APIUtil, ApiRole}
import code.api.v3_1_0.CreateAccountResponseJsonV310
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DeleteCustomerCascadeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DeleteCustomerCascadeTest.scala
index 9717b87a35..3efc6819e9 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DeleteCustomerCascadeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DeleteCustomerCascadeTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.{CanDeleteCustomerCascade, CanDeleteTransactionCascade}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DeleteProductCascadeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DeleteProductCascadeTest.scala
index 3746cef2cc..ed370272fd 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DeleteProductCascadeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DeleteProductCascadeTest.scala
@@ -6,7 +6,7 @@ import code.api.util.ApiRole.CanDeleteProductCascade
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.util.{APIUtil, ApiRole}
import code.api.v3_1_0.{PostPutProductJsonV310, ProductJsonV310}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DeleteTransactionCascadeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DeleteTransactionCascadeTest.scala
index dd140bbf03..5f4acc1616 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DeleteTransactionCascadeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DeleteTransactionCascadeTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.CanDeleteTransactionCascade
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.metadata.comments.MappedComment
import code.metadata.narrative.MappedNarrative
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DirectDebitTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DirectDebitTest.scala
index 7248ec5c07..f780ec8379 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DirectDebitTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DirectDebitTest.scala
@@ -8,7 +8,7 @@ import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanCreateDirectDebitAtOneBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{NoViewPermission, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DoubleEntryTransactionTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DoubleEntryTransactionTest.scala
index ac7edf6524..b38b8901d3 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DoubleEntryTransactionTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DoubleEntryTransactionTest.scala
@@ -4,7 +4,7 @@ import code.api.Constant
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNoPermissionAccessView, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AccountId, BankId, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DynamicEntityTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DynamicEntityTest.scala
index ca1cec323e..5ff9137de0 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DynamicEntityTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DynamicEntityTest.scala
@@ -30,7 +30,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.JsonDSL._
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DynamicIntegrationTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DynamicIntegrationTest.scala
index 45a904fe60..5eea4d9e0f 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DynamicIntegrationTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DynamicIntegrationTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ExampleValue._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.endpointMapping.EndpointMappingCommons
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DynamicMessageDocTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DynamicMessageDocTest.scala
index 8935de7b33..e5bc7448bd 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DynamicMessageDocTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DynamicMessageDocTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, UserHasMissingRoles, DynamicMessageDocNotFound}
import code.api.util.{ApiRole, CallContext}
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.bankconnectors.DynamicConnector
import code.dynamicMessageDoc.{DynamicMessageDocProvider, JsonDynamicMessageDoc}
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DynamicResourceDocTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DynamicResourceDocTest.scala
index a482557a18..01460e918d 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DynamicResourceDocTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DynamicResourceDocTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, DynamicResourceDocAlreadyExists, DynamicResourceDocNotFound, UserHasMissingRoles}
import code.api.util.ApiRole
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.dynamicResourceDoc.JsonDynamicResourceDoc
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/DynamicendPointsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/DynamicendPointsTest.scala
index fa1e108a52..472566d6c0 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/DynamicendPointsTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/DynamicendPointsTest.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{DynamicEndpointExists, EndpointMappingNotFoundByOperationId, InvalidMyDynamicEndpointUser, UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.util.ExampleValue
import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocsJson
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.dynamic.endpoint.APIMethodsDynamicEndpoint.ImplementationsDynamicEndpoint
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingBankLevelTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingBankLevelTest.scala
index cacded65e2..63e75a7b71 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingBankLevelTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingBankLevelTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.util.ExampleValue.endpointMappingRequestBodyExample
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.endpointMapping.EndpointMappingCommons
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingTest.scala
index cc7dc6ef88..a4e736b9fd 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/EndpointMappingTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.util.ExampleValue.endpointMappingRequestBodyExample
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.endpointMapping.EndpointMappingCommons
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/EndpointTagTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/EndpointTagTest.scala
index 1dee578409..955deccf34 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/EndpointTagTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/EndpointTagTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/EntitlementTests.scala b/obp-api/src/test/scala/code/api/v4_0_0/EntitlementTests.scala
index e25efe7c70..502f9281e2 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/EntitlementTests.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/EntitlementTests.scala
@@ -11,7 +11,7 @@ import code.setup.DefaultUsers
import code.api.util.APIUtil.OAuth._
import code.api.util.ExampleValue.bankIdExample
import code.api.v2_0_0.CreateEntitlementJSON
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/FirehoseTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/FirehoseTest.scala
index cb2e3bed8c..e27a67752b 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/FirehoseTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/FirehoseTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.CanUseAccountFirehoseAtAnyBank
import code.api.util.ErrorMessages.AccountFirehoseNotAllowedOnThisInstance
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.PropsReset
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ForceErrorValidationTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ForceErrorValidationTest.scala
index 5bbe3375e2..0ff0103749 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ForceErrorValidationTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ForceErrorValidationTest.scala
@@ -5,9 +5,9 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations2_2_0
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.dynamic.endpoint.APIMethodsDynamicEndpoint.ImplementationsDynamicEndpoint
import code.api.dynamic.entity.APIMethodsDynamicEntity.ImplementationsDynamicEntity
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
index 98eb9c05fd..6fb5ff059a 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
@@ -27,7 +27,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil
import code.api.util.ApiRole._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.PropsReset
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationPublicPropTrueTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationPublicPropTrueTest.scala
new file mode 100644
index 0000000000..836cd789ff
--- /dev/null
+++ b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationPublicPropTrueTest.scala
@@ -0,0 +1,122 @@
+package code.api.v4_0_0
+
+import code.api.util.APIUtil.OAuth._
+import code.api.util.ErrorMessages._
+import code.api.util.ApiRole
+import code.entitlement.Entitlement
+import code.setup.APIResponse
+import com.openbankproject.commons.model.ErrorMessage
+import com.openbankproject.commons.util.ApiVersion
+import com.openbankproject.commons.util.json
+import org.json4s.JArray
+import org.json4s.JString
+import org.scalatest.Tag
+
+// Boots its own JVM with read_json_schema_validation_requires_role forced true, via
+// OBP_READ_JSON_SCHEMA_VALIDATION_REQUIRES_ROLE (see run_tests_parallel.sh and the CI job that
+// runs this class in isolation). The prop's effect is baked into Http4s400's ResourceDoc error
+// list at object-initialization time, so a single running JVM can only ever observe one value of
+// it - this class exists to observe the true branch while JsonSchemaValidationTest observes the
+// (default) false branch in every ordinary shard.
+class JsonSchemaValidationPublicPropTrueTest extends V400ServerSetup {
+
+ object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString)
+ object PropGatedPublicEndpoint extends Tag("PropGatedPublicEndpoint")
+
+ private val mockOperationId = "MOCK_OPERATION_ID"
+
+ // Same fixture JsonSchemaValidationTest uses — createJsonSchemaValidation validates the
+ // incoming schema itself, so an under-specified schema (e.g. missing "required") 400s here
+ // for reasons unrelated to what this test is actually checking.
+ private val jsonSchemaFooBar =
+ """
+ |{
+ | "$schema": "http://json-schema.org/draft-07/schema",
+ | "$id": "http://example.com/example.json",
+ | "type": "object",
+ | "title": "The root schema",
+ | "description": "The root schema comprises the entire JSON document.",
+ | "examples": [
+ | {
+ | "name": "James Brown",
+ | "number": 698761728
+ | }
+ | ],
+ | "required": [
+ | "name",
+ | "number"
+ | ],
+ | "properties": {
+ | "name": {
+ | "type": "string",
+ | "description": "An explanation about the purpose of this instance.",
+ | "examples": [
+ | "James Brown"
+ | ]
+ | },
+ | "number": {
+ | "type": "integer",
+ | "description": "An explanation about the purpose of this instance.",
+ | "maximum": 698761730,
+ | "minimum": 10,
+ | "examples": [
+ | 698761728
+ | ]
+ | }
+ | },
+ | "additionalProperties": true
+ |}
+ |""".stripMargin
+
+ private def addEntitlement(role: ApiRole) =
+ Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, role.toString)
+
+ private def addOneValidation(schema: String, operationId: String): APIResponse = {
+ addEntitlement(ApiRole.canCreateJsonSchemaValidation)
+ val request = (v4_0_0_Request / "management" / "json-schema-validations" / operationId).POST <@ user1
+ val response = makePostRequest(request, schema)
+ response.code should equal(201)
+ response
+ }
+
+ feature(s"test GET /endpoints/json-schema-validations version $VersionOfApi - read_json_schema_validation_requires_role=true") {
+ scenario("Anonymous access is rejected when the prop requires authentication", PropGatedPublicEndpoint, VersionOfApi) {
+ When("We make an anonymous request to the public endpoint")
+ val request = (v4_0_0_Request / "endpoints" / "json-schema-validations").GET
+ val response = makeGetRequest(request)
+ Then("We should get a 401")
+ response.code should equal(401)
+ response.body.extract[ErrorMessage].message should equal(AuthenticatedUserIsRequired)
+ }
+
+ // user2 deliberately: the setup below grants roles to user1, so asserting the 403 as user1
+ // could not tell "the role is required" apart from "some role user1 already holds suffices".
+ scenario("Authenticated access without the role is rejected when the prop requires the role", PropGatedPublicEndpoint, VersionOfApi) {
+ addOneValidation(jsonSchemaFooBar, mockOperationId)
+
+ When("We make an authenticated request as a user holding no entitlement")
+ val request = (v4_0_0_Request / "endpoints" / "json-schema-validations").GET <@ user2
+ val response = makeGetRequest(request)
+ Then("We should get a 403 naming the missing role")
+ response.code should equal(403)
+ response.body.extract[ErrorMessage].message should include(
+ ApiRole.canGetJsonSchemaValidation.toString)
+ }
+
+ scenario("Authenticated access with the role succeeds when the prop requires the role", PropGatedPublicEndpoint, VersionOfApi) {
+ addOneValidation(jsonSchemaFooBar, mockOperationId)
+ addEntitlement(ApiRole.canGetJsonSchemaValidation)
+
+ When("We make an authenticated request as a user holding the role")
+ val request = (v4_0_0_Request / "endpoints" / "json-schema-validations").GET <@ user1
+ val response = makeGetRequest(request)
+ Then("We should get a 200")
+ response.code should equal(200)
+ val validations = response.body \ "json_schema_validations"
+ validations shouldBe a[JArray]
+ val validation = validations(0)
+ validation \ "operation_id" should equal(JString(mockOperationId))
+ validation \ "json_schema" should equal(json.parse(jsonSchemaFooBar))
+ }
+ }
+}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala
index e1cb541449..1e10ff6299 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala
@@ -5,8 +5,8 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations2_2_0
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/LockUserTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/LockUserTest.scala
index a579885a5d..d799850fc9 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/LockUserTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/LockUserTest.scala
@@ -3,7 +3,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanLockUser
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotFoundByProviderAndUsername, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/MakerCheckerTransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/MakerCheckerTransactionRequestTest.scala
index 93debfd372..0a2560f6d6 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/MakerCheckerTransactionRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/MakerCheckerTransactionRequestTest.scala
@@ -9,7 +9,7 @@ import code.api.util.ErrorMessages._
import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140
import code.api.v2_0_0.TransactionRequestBodyJsonV200
import code.api.v2_1_0._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.model.BankAccountX
import code.setup.DefaultUsers
import code.views.system.ViewPermission
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/MapperDatabaseInfoTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/MapperDatabaseInfoTest.scala
index 7fc0767357..8205bf7936 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/MapperDatabaseInfoTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/MapperDatabaseInfoTest.scala
@@ -3,7 +3,7 @@ package code.api.v4_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetDatabaseInfo
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/MySpaceTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/MySpaceTest.scala
index d34775a045..8f556fdab8 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/MySpaceTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/MySpaceTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.AuthenticatedUserIsRequired
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.common.Box
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/PasswordRecoverTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/PasswordRecoverTest.scala
index 6e3495383a..c9c79f51cc 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/PasswordRecoverTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/PasswordRecoverTest.scala
@@ -33,7 +33,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.model.dataAccess.{AuthUser, ResourceUser}
import code.users.Users
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ProductFeeTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ProductFeeTest.scala
index 2ba3315370..7a56eeaaa5 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ProductFeeTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ProductFeeTest.scala
@@ -31,7 +31,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.productFeeJsonV400
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{ProductFeeNotFoundById, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ProductTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ProductTest.scala
index 6c3276f044..f6cb8ba318 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ProductTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ProductTest.scala
@@ -30,7 +30,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.ErrorMessages._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/RateLimitingTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/RateLimitingTest.scala
index 0c92ac817f..5de3cda87b 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/RateLimitingTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/RateLimitingTest.scala
@@ -31,8 +31,8 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanUpdateRateLimits, canCreateDynamicEndpoint}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.util.{ApiRole, ExampleValue, RateLimitingUtil}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0.getCurrentUser
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0.getCurrentUser
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.setup.PropsReset
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/ScopesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/ScopesTest.scala
index d851e33f78..c5d5b8045a 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/ScopesTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/ScopesTest.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole
import code.api.util.ApiRole.{CanCreateAnyTransactionRequest, CanCreateScopeAtAnyBank, CanDeleteScopeAtAnyBank, CanGetAnyUser, CanGetEntitlementsForAnyUserAtAnyBank}
import code.api.util.ErrorMessages._
import code.api.v3_0_0.{CreateScopeJson, ScopeJsons}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.scope.Scope
import code.setup.APIResponse
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/SettlementAccountTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/SettlementAccountTest.scala
index 4c626c841b..d675f69b5e 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/SettlementAccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/SettlementAccountTest.scala
@@ -9,7 +9,7 @@ import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequ
import code.api.util.{APIUtil, ApiRole, NewStyle}
import code.api.v2_0_0.BasicAccountJSON
import code.api.v3_1_0.{CreateAccountResponseJsonV310, PostPutProductJsonV310, ProductJsonV310}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.enums.AccountRoutingScheme
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/StandingOrderTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/StandingOrderTest.scala
index a5a1acbca2..8abd11a60e 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/StandingOrderTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/StandingOrderTest.scala
@@ -8,7 +8,7 @@ import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanCreateStandingOrderAtOneBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{NoViewPermission, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/TransactionAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/TransactionAttributesTest.scala
index d5d81d2efe..1591bdcade 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/TransactionAttributesTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/TransactionAttributesTest.scala
@@ -6,7 +6,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{BankId, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala
index c229510c56..e22cb4bc89 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala
@@ -7,7 +7,7 @@ import code.api.util.APIUtil
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala
index 08bf4d59e9..dbc373a684 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala
@@ -16,7 +16,7 @@ import code.api.util.{APIUtil, ErrorMessages}
import code.api.v1_4_0.JSONFactory1_4_0.{ChallengeAnswerJSON, TransactionRequestAccountJsonV140}
import code.api.v2_0_0.TransactionRequestBodyJsonV200
import code.api.v2_1_0._
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v5_0_0.PhysicalCardJsonV500
import code.api.v5_1_0.{AgentJsonV510, PutAgentJsonV510}
import code.bankconnectors.Connector
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala
index 4937100d75..58d8405055 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala
@@ -5,7 +5,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.users.UserAttribute
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserCustomerLinkTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserCustomerLinkTest.scala
index 71063059cc..ef0ee25103 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/UserCustomerLinkTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/UserCustomerLinkTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateUserCustomerLink, CanDeleteUserCustomerLink, CanGetUserCustomerLink}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v2_0_0.UserCustomerLinksJson
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserInvitationApiTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserInvitationApiTest.scala
index c4615b4c71..c09e9231e3 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/UserInvitationApiTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/UserInvitationApiTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole.{CanCreateUserInvitation, CanGetUserInvitation}
import code.api.util.ErrorMessages.{CannotGetUserInvitation, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.users.UserInvitationProvider
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserTest.scala
index 42677cc04b..f1db647c2e 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/UserTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/UserTest.scala
@@ -5,7 +5,7 @@ import java.util.UUID
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetAnyUser
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired, attemptedToOpenAnEmptyBox}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import code.model.UserX
import code.users.Users
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/WebhooksTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/WebhooksTest.scala
index e42734c595..dadc0f6407 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/WebhooksTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/WebhooksTest.scala
@@ -30,7 +30,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.ApiRole._
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/ATMTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/ATMTest.scala
index da789d53f9..b593ac1c7e 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/ATMTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/ATMTest.scala
@@ -32,7 +32,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v3_1_0.CustomerJsonV310
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/AccountTest.scala
index c96fb08b1d..74a99758d9 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/AccountTest.scala
@@ -8,12 +8,12 @@ import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v2_0_0.BasicAccountJSON
-import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
+import code.api.v2_0_0.Http4s200.Implementations2_0_0
import code.api.v3_0_0.CoreAccountsJsonV300
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.api.v3_1_0.CreateAccountResponseJsonV310
import code.api.v4_0_0.{AccountsBalancesJsonV400, ModeratedCoreAccountJsonV400}
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/BankTests.scala b/obp-api/src/test/scala/code/api/v5_0_0/BankTests.scala
index d49f7cd0f9..9c70e09315 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/BankTests.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/BankTests.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole.CanCreateBank
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.api.util.{APIUtil, ApiRole, ErrorMessages, NewStyle}
import code.api.util.APIUtil.OAuth._
-import code.api.v5_0_0.APIMethods500.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.entitlement.Entitlement
import code.setup.{APIResponse, DefaultUsers}
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/ConsentRequestTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/ConsentRequestTest.scala
index d4ae49eba1..744c922391 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/ConsentRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/ConsentRequestTest.scala
@@ -33,9 +33,9 @@ import code.api.util.ApiRole._
import code.api.util.{APIUtil, Consent}
import code.api.util.ErrorMessages._
import code.api.v3_1_0.{PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.UsersJsonV400
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.consent.ConsentStatus
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/CustomerAccountLinkTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/CustomerAccountLinkTest.scala
index 321108311a..39b9dc2c0e 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/CustomerAccountLinkTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/CustomerAccountLinkTest.scala
@@ -2,7 +2,7 @@ package code.api.v5_0_0
import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/CustomerOverviewTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/CustomerOverviewTest.scala
index 244cd865b0..d6422fa505 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/CustomerOverviewTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/CustomerOverviewTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v3_1_0.CustomerJsonV310
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/CustomerTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/CustomerTest.scala
index aad80b568b..a2b12c7aa7 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/CustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/CustomerTest.scala
@@ -35,7 +35,7 @@ import code.api.v2_1_0.CustomerJSONs
import code.api.v3_0_0.CustomerJSONsV300
import code.api.v3_1_0.CustomerJsonV310
import code.api.v4_0_0.CustomersMinimalJsonV400
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/GetAdapterInfoTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/GetAdapterInfoTest.scala
index 9365f0a659..5eb421813c 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/GetAdapterInfoTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/GetAdapterInfoTest.scala
@@ -28,7 +28,7 @@ package code.api.v5_0_0
import code.api.util.ApiRole.canGetAdapterInfo
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v3_0_0.AdapterInfoJsonV300
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.api.util.APIUtil.OAuth._
import code.entitlement.Entitlement
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala
index 6e29e75a49..49c51c93a3 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala
@@ -30,7 +30,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetMetricsAtOneBank
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v2_1_0.MetricsJson
-import code.api.v5_0_0.APIMethods500.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.entitlement.Entitlement
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/ProductTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/ProductTest.scala
index 3ae3ad0b2c..f166609414 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/ProductTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/ProductTest.scala
@@ -30,8 +30,8 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.ApiRole._
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages._
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.api.v4_0_0.{ProductJsonV400, ProductsJsonV400}
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/UserAuthContextTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/UserAuthContextTest.scala
index 840fba41a8..f2fcf22c0c 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/UserAuthContextTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/UserAuthContextTest.scala
@@ -34,7 +34,7 @@ import code.api.util.ApiRole._
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
import code.api.v3_1_0.CustomerJsonV310
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import org.json4s.native.Serialization.write
diff --git a/obp-api/src/test/scala/code/api/v5_0_0/ViewsTests.scala b/obp-api/src/test/scala/code/api/v5_0_0/ViewsTests.scala
index c2adc72c6f..ce546b8878 100644
--- a/obp-api/src/test/scala/code/api/v5_0_0/ViewsTests.scala
+++ b/obp-api/src/test/scala/code/api/v5_0_0/ViewsTests.scala
@@ -30,7 +30,7 @@ import code.api.Constant._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.OAuth._
import code.api.v1_2_1.{PermissionJSON, PermissionsJSON}
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.setup.APIResponse
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala
index a3c07f1814..316600a3ce 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala
@@ -11,7 +11,7 @@ import code.api.util.ErrorMessages._
import code.api.v3_0_0.ViewJsonV300
import code.api.v3_1_0.CreateAccountResponseJsonV310
import code.api.v4_0_0.{AccountsMinimalJson400, RevokedJsonV400}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage}
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AccountBalanceTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AccountBalanceTest.scala
index c1544ddc31..5d7129cade 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AccountBalanceTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AccountBalanceTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages.AuthenticatedUserIsRequired
import code.api.v4_0_0.{AccountsBalancesJsonV400, BalanceJsonV400}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AccountTest.scala
index 3f6e166d55..2977ed56f7 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AccountTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetAccountsHeldAtAnyBank, CanGetAccountsHeldAtOneBank, CanSyncUser}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AgentTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AgentTest.scala
index 919826452b..8f9de9fca6 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AgentTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AgentTest.scala
@@ -3,7 +3,7 @@ package code.api.v5_1_0
import org.json4s._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{postAgentJsonV510, putAgentJsonV510}
import code.api.util.ErrorMessages.{BankNotFound, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ApiCollectionTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ApiCollectionTest.scala
index 9585702cd9..20c8aaf8ef 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ApiCollectionTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ApiCollectionTest.scala
@@ -30,9 +30,9 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v4_0_0.APIMethods400.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.{ApiCollectionJson400, ApiCollectionsJson400}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ApiTagsTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ApiTagsTest.scala
index 0ca38047e8..fed5141faa 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ApiTagsTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ApiTagsTest.scala
@@ -1,7 +1,7 @@
package code.api.v5_1_0
import code.api.util.ErrorMessages.AuthenticatedUserIsRequired
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AtmAttributeTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AtmAttributeTest.scala
index 18ada11e3e..9a3e8c6037 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AtmAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AtmAttributeTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.{ApiRole, ErrorMessages}
import code.api.util.ErrorMessages.{AtmNotFoundByAtmId, UserHasMissingRoles}
-import code.api.v5_1_0.APIMethods510.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AtmTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AtmTest.scala
index 50534663ca..ba8048779a 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/AtmTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/AtmTest.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{AtmNotFoundByAtmId, UserHasMissingRoles}
import code.api.util.ExampleValue.atmTypeExample
import code.api.util.{ApiRole, ErrorMessages}
-import code.api.v5_1_0.APIMethods510.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.atmattribute.AtmAttribute
import code.entitlement.Entitlement
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/BankAccountBalanceTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/BankAccountBalanceTest.scala
index 325ad33c4e..9a2e0600ad 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/BankAccountBalanceTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/BankAccountBalanceTest.scala
@@ -5,7 +5,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages
-import code.api.v5_1_0.APIMethods510.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala
index ebba60b518..e4cd3b0ef7 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala
@@ -32,10 +32,10 @@ import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.util.{APIUtil, Consent}
import code.api.util.APIUtil.OAuth._
-import code.api.v3_0_0.{APIMethods300, UserJsonV300}
+import code.api.v3_0_0.{Http4s300, UserJsonV300}
import code.api.v3_1_0.{ConsentJsonV310, PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310, PostConsentViewJsonV310}
-import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v3_1_0.Http4s310.Implementations3_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
@@ -57,7 +57,7 @@ class ConsentObpTest extends V510ServerSetup {
object AnswerConsentChallenge extends Tag(nameOf(Implementations3_1_0.answerConsentChallenge))
object VersionOfApi2 extends Tag(ApiVersion.v3_0_0.toString)
- object GetUserByUserId extends Tag(nameOf(APIMethods300.Implementations3_0_0.getUserByUserId))
+ object GetUserByUserId extends Tag(nameOf(Http4s300.Implementations3_0_0.getUserByUserId))
val validHeaderConsumerKey = List((RequestHeader.`Consumer-Key`, user1.map(_._1.key).getOrElse("SHOULD_NOT_HAPPEN")))
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ConsentOwnershipTests.scala b/obp-api/src/test/scala/code/api/v5_1_0/ConsentOwnershipTests.scala
index 47386f389d..f914992c54 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ConsentOwnershipTests.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ConsentOwnershipTests.scala
@@ -33,7 +33,7 @@ import code.api.util.ApiRole._
import code.api.util.Consent
import code.api.util.ErrorMessages._
import code.api.v3_1_0.{ConsentJsonV310, PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310, PostConsentViewJsonV310}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.setup.PropsReset
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ConsentsTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ConsentsTest.scala
index 6b8225113c..7a4afb71b2 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ConsentsTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ConsentsTest.scala
@@ -33,11 +33,11 @@ import code.api.util.ApiRole._
import code.api.util.Consent
import code.api.util.ErrorMessages._
import code.api.v3_1_0.{ConsentJsonV310, PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.{PutConsentStatusJsonV400, UsersJsonV400}
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
import code.api.v5_0_0.{AccountAccessV500, ConsentJsonV500, ConsentRequestResponseJson}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.consent.ConsentStatus
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ConsumerTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ConsumerTest.scala
index 92b2a6afa9..5d047d7bcf 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ConsumerTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ConsumerTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages.{InvalidJsonFormat, AuthenticatedUserIsRequired, ApplicationNotIdentified}
import code.api.v3_1_0.ConsumerJsonV310
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala
index 716ba6c172..fe447fd79f 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala
@@ -5,8 +5,8 @@ import code.api.Constant.{SYSTEM_OWNER_VIEW_ID}
import code.api.util.ErrorMessages._
import code.api.util.APIUtil.OAuth._
import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage}
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CurrenciesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CurrenciesTest.scala
index acf1b48ae3..d6dd76ea54 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/CurrenciesTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/CurrenciesTest.scala
@@ -2,7 +2,7 @@ package code.api.v5_1_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.consumer.Consumers
import code.scope.Scope
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CustomViewTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CustomViewTest.scala
index abd3f973ae..e829f4d001 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/CustomViewTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/CustomViewTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.Constant.{SYSTEM_AUDITOR_VIEW_ID, SYSTEM_MANAGE_CUSTOM_VIEWS_VIEW_ID, SYSTEM_OWNER_VIEW_ID, SYSTEM_STAGE_ONE_VIEW_ID}
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages._
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CustomerTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CustomerTest.scala
index 35d9c8a91a..bd6190f830 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/CustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/CustomerTest.scala
@@ -33,7 +33,7 @@ import code.api.util.ApiRole.CanGetCustomersAtOneBank
import code.api.util.ErrorMessages._
import code.api.v3_0_0.CustomerJSONsV300
import code.api.v3_1_0.CustomerJsonV310
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/JustInTimeEntitlementsTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/JustInTimeEntitlementsTest.scala
index d2e5176426..663d3fd417 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/JustInTimeEntitlementsTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/JustInTimeEntitlementsTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateEntitlementAtAnyBank, CanCreateEntitlementAtOneBank, CanGetAnyUser, CanGetMetricsAtOneBank}
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.api.v2_1_0.MetricsJson
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.UserJsonV400
import code.entitlement.Entitlement
import code.setup.{APIResponse, DefaultUsers}
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala
index fa7a34221d..01859acfa4 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole.{CanLockUser, CanReadUserLockedStatus, CanUnlockUse
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotFoundByProviderAndUsername, AuthenticatedUserIsRequired, UsernameHasBeenLocked}
import code.api.v3_0_0.UserJsonV300
import code.api.v3_1_0.BadLoginStatusJson
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.loginattempts.LoginAttempt
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/LogCacheEndpointTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/LogCacheEndpointTest.scala
index 388a12622b..24a9f3825f 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/LogCacheEndpointTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/LogCacheEndpointTest.scala
@@ -4,7 +4,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetSystemLogCacheAll,CanGetSystemLogCacheInfo}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/MetricTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/MetricTest.scala
index 30e255ee15..c0365b584f 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/MetricTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/MetricTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanReadAggregateMetrics
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v3_0_0.AggregateMetricJSON
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.metrics.MetricBatchWriter
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala
index ddf47dba3a..b6ab0d5a2e 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala
@@ -30,7 +30,7 @@ import code.api.util.ApiRole
import code.api.util.ApiRole.CanReadCallLimits
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
import code.api.v4_0_0.CallLimitPostJsonV400
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.consumer.Consumers
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityAttributeTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityAttributeTest.scala
index 5b1c1665a9..e0c0abcae3 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityAttributeTest.scala
@@ -5,7 +5,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages
-import code.api.v5_1_0.APIMethods510.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala
index dc017b5bda..6dfbc124d5 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala
@@ -5,7 +5,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.regulatedEntityPostJson
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateRegulatedEntity, CanDeleteRegulatedEntity, CanGetSystemIntegrity}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/ResponseHeadersTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/ResponseHeadersTest.scala
index ebc1ab362a..4bb03cf744 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/ResponseHeadersTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/ResponseHeadersTest.scala
@@ -6,7 +6,7 @@ import java.util.Date
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.OAuth._
import code.api.util.{APIUtil, ApiRole}
-import code.api.v5_1_0.APIMethods510.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.api.{RequestHeader, ResponseHeader}
import code.entitlement.Entitlement
import code.setup.{APIResponse, DefaultUsers}
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/SystemIntegrityTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/SystemIntegrityTest.scala
index fe73bd06be..696f5fc272 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/SystemIntegrityTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/SystemIntegrityTest.scala
@@ -3,7 +3,7 @@ package code.api.v5_1_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetSystemIntegrity
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala
index 2c76638438..74675a5c7a 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala
@@ -31,8 +31,8 @@ import code.api.util.ErrorMessages._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetTransactionRequestAtAnyBank, CanGetTransactionRequestAtOneBank, CanUpdateTransactionRequestStatusAtAnyBank, CanUpdateTransactionRequestStatusAtOneBank}
import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON, TransactionRequestWithChargeJSONs210}
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.enums.TransactionRequestStatus
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage, TransactionRequestAttributeJsonV400}
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala
index 10aa7bb2b5..b1860ec771 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ErrorMessages._
import code.api.v4_0_0.UsersJsonV400
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala
index 00b0d2c80f..c4c9b7a4c6 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetAnyUser, CanGetEntitlementsForAnyUserAtAnyBank, CanValidateUser}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired, attemptedToOpenAnEmptyBox}
import code.api.v3_0_0.UserJsonV300
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.model.UserX
import code.model.dataAccess.AuthUser
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala
index cc57ae70ca..90a51ede40 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala
@@ -45,13 +45,13 @@ import code.api.util.ErrorMessages._
import code.api.util.ExampleValue.counterpartyNameExample
import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON}
import code.api.v3_0_0.CoreAccountsJsonV300
-import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
+import code.api.v3_0_0.Http4s300.Implementations3_0_0
import code.api.v3_1_0.PostConsentChallengeJsonV310
-import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
+import code.api.v4_0_0.Http4s400.Implementations4_0_0
import code.api.v4_0_0.{TransactionRequestWithChargeJSON400, UsersJsonV400}
import code.api.v5_0_0.ConsentRequestResponseJson
-import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_0_0.Http4s500.Implementations5_0_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.consent.ConsentStatus
import code.entitlement.Entitlement
import code.setup.PropsReset
diff --git a/obp-api/src/test/scala/code/api/v5_1_0/WebUiPropsTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/WebUiPropsTest.scala
index 3b2c77c105..30b9b843cb 100644
--- a/obp-api/src/test/scala/code/api/v5_1_0/WebUiPropsTest.scala
+++ b/obp-api/src/test/scala/code/api/v5_1_0/WebUiPropsTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
+import code.api.v5_1_0.Http4s510.Implementations5_1_0
import code.entitlement.Entitlement
import code.webuiprops.WebUiPropsCommons
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala b/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala
index d528dd2968..89dd62e297 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{canCreateAbacRule, canExecuteAbacRule}
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala
index 479e3fb5cd..1383282a40 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala
@@ -27,7 +27,7 @@ package code.api.v6_0_0
import code.api.util.APIUtil
import code.api.util.APIUtil.OAuth._
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.util.ApiVersion
import org.scalatest.Tag
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/BankTests.scala b/obp-api/src/test/scala/code/api/v6_0_0/BankTests.scala
index 8d5bb5f3b3..245354808a 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/BankTests.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/BankTests.scala
@@ -6,7 +6,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanCreateBank
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/CacheEndpointsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/CacheEndpointsTest.scala
index f98b11794b..5fb201d06c 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/CacheEndpointsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/CacheEndpointsTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanGetCacheConfig, CanGetCacheInfo, CanInvalidateCacheNamespace}
import code.api.util.ErrorMessages.{InvalidJsonFormat, UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/CardanoTransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/CardanoTransactionRequestTest.scala
index d147ba273a..679c59839a 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/CardanoTransactionRequestTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/CardanoTransactionRequestTest.scala
@@ -41,7 +41,7 @@ import org.json4s.native.Serialization.write
import org.scalatest.Tag
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/ConsumerTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/ConsumerTest.scala
index bc45b9769a..acd6195143 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/ConsumerTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/ConsumerTest.scala
@@ -28,7 +28,7 @@ package code.api.v6_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetCurrentConsumer
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/CounterpartyAttributeTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/CounterpartyAttributeTest.scala
index 0d681bdf10..1bd62c51af 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/CounterpartyAttributeTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/CounterpartyAttributeTest.scala
@@ -6,7 +6,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/CustomViewsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/CustomViewsTest.scala
index 0220a729e7..f1af037374 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/CustomViewsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/CustomViewsTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateCustomView, CanGetCustomViews}
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.{InvalidCustomViewFormat, InvalidJsonFormat, UserHasMissingRoles}
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import code.views.system.ViewDefinition
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/CustomerTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/CustomerTest.scala
index 56a6b4a31f..4d5ed916cd 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/CustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/CustomerTest.scala
@@ -31,7 +31,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateCustomer, CanGetCustomersAtOneBank}
import code.api.util.ErrorMessages._
import code.api.v3_1_0.PostCustomerNumberJsonV310
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.api.v6_0_0.{CustomerJsonV600, CustomerJSONsV600, CustomerWithAttributesJsonV600, PostCustomerJsonV600}
import code.customer.CustomerX
import code.entitlement.Entitlement
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/DirectLoginV600Test.scala b/obp-api/src/test/scala/code/api/v6_0_0/DirectLoginV600Test.scala
index 061820515e..b78bf60747 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/DirectLoginV600Test.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/DirectLoginV600Test.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.Constant.localIdentityProvider
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages._
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.api.v3_0_0.UserJsonV300
import code.consumer.Consumers
import code.loginattempts.LoginAttempt
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/DynamicEntityTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/DynamicEntityTest.scala
index 5b93577102..beef6b4ec1 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/DynamicEntityTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/DynamicEntityTest.scala
@@ -29,7 +29,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.scope.Scope
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/GetOidcClientTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/GetOidcClientTest.scala
index f6b1d2787a..ca2f7b8db0 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/GetOidcClientTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/GetOidcClientTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetOidcClient
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/GetUserByUserIdTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/GetUserByUserIdTest.scala
index ec49f1fb07..56bd4da6fd 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/GetUserByUserIdTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/GetUserByUserIdTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetAnyUser
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/GetUsersTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/GetUsersTest.scala
index 5990e8051b..3f4f10dd68 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/GetUsersTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/GetUsersTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetAnyUser
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/GroupEntitlementsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/GroupEntitlementsTest.scala
index 3aa0c60cd2..6a15429f5a 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/GroupEntitlementsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/GroupEntitlementsTest.scala
@@ -8,7 +8,7 @@ import code.api.util.ApiRole.{
}
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/MessageDocsJsonSchemaTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/MessageDocsJsonSchemaTest.scala
index 14a5a9b2d1..8538f645be 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/MessageDocsJsonSchemaTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/MessageDocsJsonSchemaTest.scala
@@ -3,7 +3,7 @@ package code.api.v6_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole
import code.api.util.ErrorMessages.InvalidConnector
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import com.fasterxml.jackson.databind.ObjectMapper
import com.github.dwickern.macros.NameOf.nameOf
import com.networknt.schema.{JsonSchemaFactory, SpecVersion}
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/MigrationsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/MigrationsTest.scala
index a91f3c0180..31ebba4c0f 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/MigrationsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/MigrationsTest.scala
@@ -28,7 +28,7 @@ package code.api.v6_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetMigrations
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/PasswordResetTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/PasswordResetTest.scala
index 2cfcd9ebef..f1c403cf13 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/PasswordResetTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/PasswordResetTest.scala
@@ -34,7 +34,7 @@ import code.api.util.ApiRole._
import code.api.util.CertificateUtil
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages._
-import code.api.v6_0_0.APIMethods600
+import code.api.v6_0_0.Http4s600
import code.entitlement.Entitlement
import code.model.dataAccess.{AuthUser, ResourceUser}
@@ -66,9 +66,9 @@ class PasswordResetTest extends V600ServerSetup with code.setup.EnvVarOverride {
}
object VersionOfApi extends Tag(ApiVersion.v6_0_0.toString)
- object ApiEndpoint1 extends Tag(nameOf(APIMethods600.Implementations6_0_0.resetPasswordUrl))
- object ApiEndpoint2 extends Tag(nameOf(APIMethods600.Implementations6_0_0.resetPasswordUrlAnonymous))
- object ApiEndpoint3 extends Tag(nameOf(APIMethods600.Implementations6_0_0.resetPasswordComplete))
+ object ApiEndpoint1 extends Tag(nameOf(Http4s600.Implementations6_0_0.resetPasswordUrl))
+ object ApiEndpoint2 extends Tag(nameOf(Http4s600.Implementations6_0_0.resetPasswordUrlAnonymous))
+ object ApiEndpoint3 extends Tag(nameOf(Http4s600.Implementations6_0_0.resetPasswordComplete))
lazy val postUserId = UUID.randomUUID.toString
lazy val postJson = JSONFactory600.PostResetPasswordUrlJsonV600("marko", "marko@tesobe.com", postUserId)
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/RateLimitsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/RateLimitsTest.scala
index b111dddb31..17ddd27a97 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/RateLimitsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/RateLimitsTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateRateLimits, CanDeleteRateLimits, CanGetRateLimits}
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.consumer.Consumers
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/RetailAndCorporateCustomerTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/RetailAndCorporateCustomerTest.scala
index 9a875eec33..896acf2295 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/RetailAndCorporateCustomerTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/RetailAndCorporateCustomerTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateCustomer, CanGetCustomersAtOneBank}
import code.api.util.ErrorMessages._
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/SystemViewsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/SystemViewsTest.scala
index fdced1da86..13f4ec2fdf 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/SystemViewsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/SystemViewsTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetSystemViews
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/TopApisTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/TopApisTest.scala
index 6f62fffab5..fabf61b69f 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/TopApisTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/TopApisTest.scala
@@ -29,7 +29,7 @@ package code.api.v6_0_0
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanReadMetrics
import code.api.util.ErrorMessages.{UserHasMissingRoles, AuthenticatedUserIsRequired}
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala
index cb5369c5d6..0a666eeedd 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala
@@ -5,7 +5,7 @@ import code.api.Constant
import code.api.util.APIUtil.OAuth._
import code.api.util.{CallContext, ErrorMessages}
import code.api.util.ApiRole.CanVerifyUserCredentials
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.bankconnectors.Connector
import code.entitlement.Entitlement
import code.loginattempts.LoginAttempt
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyOidcClientTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyOidcClientTest.scala
index 1432c8a7cf..e1c41f6f8a 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyOidcClientTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyOidcClientTest.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanVerifyOidcClient
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala
index 901e934d2f..53239879f3 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala
@@ -7,7 +7,7 @@ import code.api.util.ApiRole
import code.api.util.ApiRole.CanVerifyUserCredentials
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.{InvalidLoginCredentials, UserHasMissingRoles, UsernameHasBeenLocked}
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.loginattempts.LoginAttempt
import code.model.dataAccess.AuthUser
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/ViewPermissionsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/ViewPermissionsTest.scala
index 4e5eb81590..6a1e5baee5 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/ViewPermissionsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/ViewPermissionsTest.scala
@@ -4,7 +4,7 @@ import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.CanGetViewPermissionsAtAllBanks
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages.UserHasMissingRoles
-import code.api.v6_0_0.APIMethods600.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.setup.DefaultUsers
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/api/v6_0_0/WebUiPropsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/WebUiPropsTest.scala
index 5fbfb0aa66..e47992112f 100644
--- a/obp-api/src/test/scala/code/api/v6_0_0/WebUiPropsTest.scala
+++ b/obp-api/src/test/scala/code/api/v6_0_0/WebUiPropsTest.scala
@@ -29,7 +29,7 @@ import org.json4s._
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
-import code.api.v6_0_0.OBPAPI6_0_0.Implementations6_0_0
+import code.api.v6_0_0.Http4s600.Implementations6_0_0
import code.entitlement.Entitlement
import code.webuiprops.WebUiPropsCommons
import com.github.dwickern.macros.NameOf.nameOf
diff --git a/obp-api/src/test/scala/code/connector/EthereumConnector_vSept2025Test.scala b/obp-api/src/test/scala/code/connector/EthereumConnector_vSept2025Test.scala
deleted file mode 100644
index f65c1bd401..0000000000
--- a/obp-api/src/test/scala/code/connector/EthereumConnector_vSept2025Test.scala
+++ /dev/null
@@ -1,116 +0,0 @@
-//package code.connector
-//
-//import code.api.util.ErrorMessages
-//import code.api.v5_1_0.V510ServerSetup
-//import code.api.v6_0_0.TransactionRequestBodyEthereumJsonV600
-//import code.bankconnectors.ethereum.EthereumConnector_vSept2025
-//import com.github.dwickern.macros.NameOf
-//import com.openbankproject.commons.model._
-//import net.liftweb.common.Full
-//import org.scalatest.Tag
-//
-//import scala.concurrent.Await
-//import scala.concurrent.duration._
-///**
-// * Minimal unit test to invoke makePaymentv210 against local Anvil.
-// * Assumptions:
-// * - ethereum.rpc.url points to http://127.0.0.1:8545
-// * - The RPC allows eth_sendTransaction (Anvil unlocked accounts)
-// * - We pass BankAccount stubs with accountId holding 0x addresses
-// */
-//class EthereumConnector_vSept2025Test extends V510ServerSetup{
-//
-// object ConnectorTestTag extends Tag(NameOf.nameOfType[EthereumConnector_vSept2025Test])
-//
-// object StubConnector extends EthereumConnector_vSept2025
-//
-// private case class StubBankAccount(id: String) extends BankAccount {
-// override val accountId: AccountId = AccountId(id)
-// override val bankId: BankId = BankId("bank-x")
-// override val accountType: String = "checking"
-// override val balance: BigDecimal = BigDecimal(0)
-// override val currency: String = "ETH"
-// override val name: String = "stub"
-// override val label: String = "stub"
-// override val number: String = "stub"
-// override val lastUpdate: java.util.Date = new java.util.Date()
-// override val accountHolder: String = "stub"
-// override val accountRoutings: List[AccountRouting] = Nil
-// override def branchId: String = "stub"
-// override def accountRules: List[AccountRule] = Nil
-// }
-//
-// feature("Anvil local Ethereum Node, need to start the Anvil, and set `ethereum.rpc.url=http://127.0.0.1:8545` in props, and prepare the from, to account") {
-//// setPropsValues("ethereum.rpc.url"-> "https://nkotb.openbankproject.com")
-// scenario("successful case", ConnectorTestTag) {
-// val from = StubBankAccount("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
-// val to = StubBankAccount("0x70997970C51812dc3A010C7d01b50e0d17dc79C8")
-// val amount = BigDecimal("0.0001")
-//
-// val trxBody = TransactionRequestBodyEthereumJsonV600(
-// to = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
-// value = AmountOfMoneyJsonV121("ETH", amount.toString),
-// description="test"
-// )
-//
-// //// This is only for testing; you can comment it out when the local Anvil is running.
-//// val resF = StubConnector.makePaymentv210(
-//// from,
-//// to,
-//// TransactionRequestId(java.util.UUID.randomUUID().toString),
-//// trxBody,
-//// amount,
-//// "test",
-//// TransactionRequestType("ETH_SEND_TRANSACTION"),
-//// "none",
-//// None
-//// )
-////
-//// val res = Await.result(resF, 10.seconds)
-//// res._1 shouldBe a[Full[_]]
-//// val txId = res._1.openOrThrowException(ErrorMessages.UnknownError)
-//// txId.value should startWith("0x")
-// }
-// }
-//
-// feature("need to start the Anvil, and set `ethereum.rpc.url=https://nkotb.openbankproject.com` in props, and prepare the from, to accounts and the rawTx") {
-//// setPropsValues("ethereum.rpc.url"-> "http://127.0.0.1:8545")
-// scenario("successful case", ConnectorTestTag) {
-//
-// val from = StubBankAccount("0xf17f52151EbEF6C7334FAD080c5704D77216b732")
-// val to = StubBankAccount("0x627306090abaB3A6e1400e9345bC60c78a8BEf57")
-// val amount = BigDecimal("0.0001")
-//
-// // Use a fixed rawTx variable for testing eth_sendRawTransaction path (no external params)
-// val rawTx = "0xf86a058203e882520894627306090abab3a6e1400e9345bc60c78a8bef57872386f26fc1000080820ff5a06de864bc825c4e976f5c432d0a57e3b3c9e19ec9843b5bb893a78a1389be650ea04fa063aba3984ff97e6454595f170e17e117f046568960aacf96f223c71ca0e2"
-//
-// val trxBody = TransactionRequestBodyEthereumJsonV600(
-// params= Some(rawTx),
-// to = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
-// value = AmountOfMoneyJsonV121("ETH", amount.toString),
-// description="test"
-// )
-////
-//// // Enable integration test against private chain
-//// val resF = StubConnector.makePaymentv210(
-//// from,
-//// to,
-//// TransactionRequestId(java.util.UUID.randomUUID().toString),
-//// trxBody,
-//// amount,
-//// "test",
-//// TransactionRequestType("ETH_SEND_RAW_TRANSACTION") ,
-//// "none",
-//// None
-//// )
-////
-//// val res = Await.result(resF, 30.seconds)
-//// res._1 shouldBe a [Full[_]]
-//// val txId = res._1.openOrThrowException(ErrorMessages.UnknownError)
-//// txId.value should startWith ("0x")
-// }
-// }
-//
-//}
-//
-//
diff --git a/obp-api/src/test/scala/code/connector/MessageDocTest.scala b/obp-api/src/test/scala/code/connector/MessageDocTest.scala
index 5dbadf32e3..e8fa3dac86 100644
--- a/obp-api/src/test/scala/code/connector/MessageDocTest.scala
+++ b/obp-api/src/test/scala/code/connector/MessageDocTest.scala
@@ -2,7 +2,7 @@ package code.connector
import org.json4s._
import code.api.v2_2_0.JSONFactory220.MessageDocJson
-import code.api.v2_2_0.OBPAPI2_2_0.Implementations2_2_0
+import code.api.v2_2_0.Http4s220.Implementations2_2_0
import code.api.v2_2_0.V220ServerSetup
import code.bankconnectors.LocalMappedConnector
import code.setup.DefaultUsers
diff --git a/obp-api/src/test/scala/code/connector/MockedJune2017Connector.scala b/obp-api/src/test/scala/code/connector/MockedJune2017Connector.scala
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/obp-api/src/test/scala/code/external/API3_0_0Test.scala b/obp-api/src/test/scala/code/external/API3_0_0Test.scala
deleted file mode 100644
index 3b9a5f7a0b..0000000000
--- a/obp-api/src/test/scala/code/external/API3_0_0Test.scala
+++ /dev/null
@@ -1,159 +0,0 @@
-///**
-//Open Bank Project - API
-//Copyright (C) 2011-2019, TESOBE GmbH
-//
-//This program is free software: you can redistribute it and/or modify
-//it under the terms of the GNU Affero General Public License as published by
-//the Free Software Foundation, either version 3 of the License, or
-//(at your option) any later version.
-//
-//This program is distributed in the hope that it will be useful,
-//but WITHOUT ANY WARRANTY; without even the implied warranty of
-//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-//GNU Affero General Public License for more details.
-//
-//You should have received a copy of the GNU Affero General Public License
-//along with this program. If not, see .
-//
-//Email: contact@tesobe.com
-//TESOBE GmbH
-//Osloerstrasse 16/17
-//Berlin 13359, Germany
-//
-// This product includes software developed at
-// TESOBE (http://www.tesobe.com/)
-// by
-// Simon Redfern : simon AT tesobe DOT com
-// Stefan Bethge : stefan AT tesobe DOT com
-// Everett Sochowski : everett AT tesobe DOT com
-// Ayoub Benali: ayoub AT tesobe DOT com
-//
-// */
-//package code.external
-//
-//import java.net.URL
-//
-//import code.api.v1_2._
-//import code.api.v3_0_0.V300ServerSetup
-//import code.setup.{APIResponse, DefaultUsers, User1AllPrivileges}
-//import org.json4s._
-//import net.liftweb.util.Helpers._
-//import org.scalatest._
-//
-//import scala.io.Source
-//
-//
-//class API3_0_0Test extends User1AllPrivileges with V300ServerSetup with DefaultUsers {
-//
-// /************************* test tags ************************/
-//
-// /**
-// * Example: To run tests with tag "ExternalTest":
-// * mvn test -D ExternalTest
-// *
-// * This is made possible by the scalatest maven plugin
-// */
-// object ExternalTest extends Tag("code.external")
-//
-//
-//
-// /********************* API test methods ********************/
-//
-// def getAPIInfo : APIResponse = {
-// val request = v3_0RequestExternal
-// makeGetRequest(request)
-// }
-//
-// def getBanksInfo : APIResponse = {
-// val request = v3_0RequestExternal / "banks"
-// makeGetRequest(request)
-// }
-//
-// def getBankInfo(bankId : String) : APIResponse = {
-// val request = v3_0RequestExternal / "banks" / bankId
-// makeGetRequest(request)
-// }
-//
-//
-//
-// feature("base line URL works"){
-// scenario("we get the api information", ExternalTest) {
-// Given("We will not use an access token")
-// When("the request is sent")
-// val reply = getAPIInfo
-// Then("we should get a 200 ok code")
-// reply.code should equal (200)
-// val apiInfo = reply.body.extract[APIInfoJSON]
-// apiInfo.version should equal ("v3.0.0")
-// }
-// }
-//
-// feature("Information about the hosted banks"){
-//
-// var banksIds:List[String] = Nil
-//
-// scenario("We get the hosted banks information", ExternalTest) {
-// Given("We will not use an access token")
-// When("the request is sent")
-// val reply: APIResponse = getBanksInfo
-// Then("we should get a 200 ok code")
-// reply.code should equal (200)
-// val banksInfo = reply.body.extract[code.api.v1_2_1.BanksJSON]
-// banksInfo.banks.foreach(b => {
-// b.id.nonEmpty should equal (true)
-// })
-//
-// // Create json file and store all banks
-// import java.io._
-// val pw = new PrintWriter(new File(server.externalHost.getOrElse("") + "-banks.json"))
-// pw.write(prettyRender(reply.body))
-// pw.close
-//
-// // Parse response to get list of bank ids
-// banksIds = for {
-// JArray(banks) <- reply.body \\ "banks"
-// JObject(bank) <- banks
-// JField("id", JString(id)) <- bank
-// } yield id
-//
-//
-// // Try to get one by one bank from the list
-// for(bankId <- banksIds){
-// val reply = getBankInfo(bankId)
-// Then("we should get a 200 ok code")
-// reply.code should equal (200)
-// val bankInfo = reply.body.extract[code.api.v1_2_1.BankJSON]
-// bankInfo.id.nonEmpty should equal (true)
-// }
-//
-// // Get data from internal json file in order to compare they with external obtained data
-// val nameOfJsonFile: String = server.externalHost.getOrElse("") + ".json"
-// val x: URL = getClass().getClassLoader().getResource(nameOfJsonFile)
-// val dataAsJsonString: String = Source.fromURL(x).mkString
-// val dataAsJsonAST = parse(dataAsJsonString)
-//
-// val banksIdsFromJson = for {
-// JArray(banks) <- dataAsJsonAST \\ "banks"
-// JObject(bank) <- banks
-// JField("id", JString(id)) <- bank
-// } yield id
-//
-// Then("Bank ids from internal json file have to be the same as external data")
-// banksIdsFromJson should equal(banksIds)
-// }
-// }
-//
-// feature("Information about one hosted bank"){
-// scenario("we don't get the hosted bank information", ExternalTest) {
-// Given("We will not use an access token and request a random bankId")
-// When("the request is sent")
-// val reply = getBankInfo(randomString(10))
-// Then("we should get a 400 code")
-// reply.code should equal (400)
-// And("we should get an error message")
-// reply.body.extract[ErrorMessage].error.nonEmpty should equal (true)
-// }
-// }
-//
-//
-//}
diff --git a/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala b/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala
index 1ea667182f..3b3eeab53d 100644
--- a/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala
+++ b/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala
@@ -32,7 +32,7 @@ import code.api.UKOpenBanking.v3_1_0.Http4sUKOBv310AccountAccess
import code.api.berlin.group.ConstantsBG
import code.api.berlin.group.v1_3.Http4sBGv13AIS
import code.api.util._
-import code.api.v4_0_0.{Http4s400, OBPAPI4_0_0, V400ServerSetup}
+import code.api.v4_0_0.{Http4s400, V400ServerSetup}
import code.setup.PropsReset
import code.views.system.ViewDefinition
import com.openbankproject.commons.util.ApiVersion
diff --git a/obp-api/src/test/scala/code/util/FrozenClassTest.scala b/obp-api/src/test/scala/code/util/FrozenClassTest.scala
index a7a7a5b7fd..930f216605 100644
--- a/obp-api/src/test/scala/code/util/FrozenClassTest.scala
+++ b/obp-api/src/test/scala/code/util/FrozenClassTest.scala
@@ -13,7 +13,7 @@ class FrozenClassTest extends ServerSetup {
feature("Frozen version apis not changed") {
- scenario(s"count of STABLE OBPAPIxxxx should not be reduce, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
+ scenario(s"count of STABLE api versions should not be reduce, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
val persistedStableVersions = persistedVersionToEndpointNames.map(_._1).toSet
val currentStableVersions = versionToEndpointNames.map(_._1).toSet
@@ -22,7 +22,7 @@ class FrozenClassTest extends ServerSetup {
increasedVersions should equal(Set.empty[ApiVersion])
}
- scenario(s"count of STABLE OBPAPIxxxx should not be increased, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
+ scenario(s"count of STABLE api versions should not be increased, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
val persistedStableVersions = persistedVersionToEndpointNames.map(_._1).toSet
val currentStableVersions = versionToEndpointNames.map(_._1).toSet
@@ -30,7 +30,7 @@ class FrozenClassTest extends ServerSetup {
reducedVersions should equal(Set.empty[ApiVersion])
}
- scenario(s"api count of STABLE value of OBPAPIxxxx#versionStatus should not be reduce, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
+ scenario(s"api count of versions with STABLE versionStatus should not be reduce, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
val reducedApis = for {
(pVersion, pEndpointNames) <- persistedVersionToEndpointNames
(version, endpointNames) <- versionToEndpointNames
@@ -43,7 +43,7 @@ class FrozenClassTest extends ServerSetup {
reducedApis should equal(Nil)
}
- scenario(s"api count of STABLE value of OBPAPIxxxx#versionStatus should not be increased, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
+ scenario(s"api count of versions with STABLE versionStatus should not be increased, if pretty sure need modify it, please run ${FrozenClassUtil.sourceName}", FrozenClassTag) {
val increasedApis = for {
(pVersion, pEndpointNames) <- persistedVersionToEndpointNames
(version, endpointNames) <- versionToEndpointNames
diff --git a/obp-api/src/test/scala/code/util/FrozenClassUtil.scala b/obp-api/src/test/scala/code/util/FrozenClassUtil.scala
index fd463014dc..ac45292c6a 100644
--- a/obp-api/src/test/scala/code/util/FrozenClassUtil.scala
+++ b/obp-api/src/test/scala/code/util/FrozenClassUtil.scala
@@ -5,7 +5,7 @@ import java.net.URI
import code.TestServer
import com.openbankproject.commons.util.ApiVersion
-import code.api.util.VersionedOBPApis
+import code.api.util.http4s.Http4sResourceDocAggregation
import com.openbankproject.commons.util.ReflectUtils
import net.liftweb.common.Loggable
import org.apache.commons.io.IOUtils
@@ -41,18 +41,21 @@ object FrozenClassUtil extends Loggable{
* @return frozen api information, include api names of given api version and frozen class metadata
*/
def getFrozenApiInfo: (List[(ApiVersion, Set[String])], Map[String, Map[String, String]]) = {
- val versionedOBPApisList: List[VersionedOBPApis] = ClassScanUtils.getSubTypeObjects[VersionedOBPApis]
- .filter(_.versionStatus == "STABLE")
+ // Was a classpath scan for VersionedOBPApis implementors, which meant the OBPAPIx_x_x
+ // aggregator objects. Those are gone; Http4sResourceDocAggregation.allVersions is the same
+ // enumeration made explicit, carrying each version's status and cumulative doc catalog.
+ val stableVersions: List[Http4sResourceDocAggregation.VersionedCatalog] =
+ Http4sResourceDocAggregation.allVersions.filter(_.versionStatus == "STABLE")
- val versionToEndpointNames: List[(ApiVersion, Set[String])] = versionedOBPApisList
+ val versionToEndpointNames: List[(ApiVersion, Set[String])] = stableVersions
.map(it => {
val version = it.version
- val currentVersionApis = it.allResourceDocs.filter(version == _.implementedInApiVersion).toSet
+ val currentVersionApis = it.docs().filter(version == _.implementedInApiVersion).toSet
(version, currentVersionApis.map(_.partialFunctionName))
})
- val allFreezingTypes: Set[Type] = versionedOBPApisList
- .flatMap(_.allResourceDocs)
+ val allFreezingTypes: Set[Type] = stableVersions
+ .flatMap(_.docs())
.flatMap(it => it.exampleRequestBody :: it.successResponseBody :: Nil)
.filter(ReflectUtils.isObpObject(_))
.map(ReflectUtils.getType(_))
diff --git a/run_tests_parallel.sh b/run_tests_parallel.sh
index b37ff9e29a..9e804e2536 100755
--- a/run_tests_parallel.sh
+++ b/run_tests_parallel.sh
@@ -214,6 +214,12 @@ run_shard() {
# fallback, so DynamicUtilTest / ConnectorMethodTest / AbacRuleTests /
# DynamicResourceDocTest / DynamicMessageDocTest / DynamicCodeKillSwitchTest's ON
# scenarios need this set explicitly or they fail locally with OBP-50020.
+ # OBP_BERLIN_GROUP_V1_3_ALIAS_PATH mirrors CI's berlin_group_v1_3_alias_path=0.6/v1
+ # (injected by both workflows' "Setup props" step): without it, OBP_BERLIN_GROUP_1_3_Alias
+ # reports an empty ScannedApiVersion("","","") and ScannedApis.isAddressable filters it
+ # out of versionMapScannedApis entirely, so ApiVersionUtilsTest's `versions.length shouldBe(21)`
+ # sees only 20 (CI green, local red) -- confirmed by reproducing the failure on a clean
+ # checkout with this var unset, then reproducing the pass with it set.
# -pl obp-commons,obp-api mirrors CI: obp-commons' own util suites run on whichever
# shard's filter matches com.openbankproject.* (the shard-4 catch-all); on every other
# shard the filter matches nothing in obp-commons -> 0 tests there.
@@ -239,6 +245,7 @@ run_shard() {
OBP_MAIL_TEST_MODE="true" \
OBP_DYNAMIC_CODE_SANDBOX_PERMISSIONS='[new java.net.NetPermission("specifyStreamHandler"), new java.lang.reflect.ReflectPermission("suppressAccessChecks"), new java.lang.RuntimePermission("getenv.*"), new java.lang.RuntimePermission("accessDeclaredMembers"), new java.lang.RuntimePermission("getClassLoader")]' \
OBP_ALLOW_USER_GENERATED_SCALA_CODE="true" \
+ OBP_BERLIN_GROUP_V1_3_ALIAS_PATH="0.6/v1" \
OBP_API_INSTANCE_ID="shard_${n}_${port}" \
"$TIMEOUT_BIN" 1200 mvn scalatest:test -pl obp-commons,obp-api -DfailIfNoTests=false \
"-DwildcardSuites=${filter}" \
@@ -437,13 +444,69 @@ else
TOTAL_SHARDS=4
fi
+# PropGatedPublicEndpoint: JsonSchemaValidationPublicPropTrueTest /
+# AuthenticationTypeValidationPublicPropTrueTest need
+# read_json_schema_validation_requires_role / read_authentication_type_validation_requires_role
+# forced true. That value is baked into Http4s400's ResourceDoc error list at object-init time, so
+# it needs its own JVM (pom.xml's default tagsToExclude skips this tag in every shard above, which
+# all boot with the props unset i.e. false). Run sequentially, after the main shards, so it shares
+# no DB connection pool contention with them; its surefire XML lands in the same
+# obp-api/target/surefire-reports directory the audit below already scans, so no separate
+# reporting path is needed.
+# Shard wall-clock is taken before the sequential step below, so the figure printed
+# next to the per-shard timings covers the same work they do.
+SHARDS_END=$(date +%s)
+
+echo ""
+echo "Running PropGatedPublicEndpoint tests (prop=true JVM)..."
+# Port allocation failure records a failing RC instead of exiting: the four shards
+# have already run by this point, and a hard exit here would skip the summary,
+# the per-shard failure diagnostics and the Surefire audit below — throwing away
+# their results over an unrelated transient.
+if ! alloc_free_port; then
+ echo " ✗ PropGatedPublicEndpoint tests skipped — could not allocate a test port"
+ PROP_RC=1
+else
+ PROP_PORT=$ALLOC_PORT
+ if ! alloc_free_port; then
+ echo " ✗ PropGatedPublicEndpoint tests skipped — could not allocate an http4s port"
+ PROP_RC=1
+ else
+ PROP_HTTP4S_PORT=$ALLOC_PORT
+ MAVEN_OPTS="$MVN_OPTS" \
+ OBP_TESTS_PORT="${PROP_PORT}" \
+ OBP_HOSTNAME="http://localhost:${PROP_PORT}" \
+ OBP_HTTP4S_TEST_PORT="${PROP_HTTP4S_PORT}" \
+ OBP_MAIL_TEST_MODE="true" \
+ OBP_DYNAMIC_CODE_SANDBOX_PERMISSIONS='[new java.net.NetPermission("specifyStreamHandler"), new java.lang.reflect.ReflectPermission("suppressAccessChecks"), new java.lang.RuntimePermission("getenv.*"), new java.lang.RuntimePermission("accessDeclaredMembers"), new java.lang.RuntimePermission("getClassLoader")]' \
+ OBP_ALLOW_USER_GENERATED_SCALA_CODE="true" \
+ OBP_BERLIN_GROUP_V1_3_ALIAS_PATH="0.6/v1" \
+ OBP_API_INSTANCE_ID="prop_gated_${PROP_PORT}" \
+ OBP_READ_JSON_SCHEMA_VALIDATION_REQUIRES_ROLE="true" \
+ OBP_READ_AUTHENTICATION_TYPE_VALIDATION_REQUIRES_ROLE="true" \
+ "$TIMEOUT_BIN" 300 mvn scalatest:test -pl obp-api -DfailIfNoTests=false \
+ "-DwildcardSuites=code.api.v4_0_0.JsonSchemaValidationPublicPropTrueTest,code.api.v4_0_0.AuthenticationTypeValidationPublicPropTrueTest" \
+ -DtagsToInclude=PropGatedPublicEndpoint -Dtest.tagsToExclude= \
+ > test-results/parallel/prop_gated_public_endpoint.log 2>&1
+ PROP_RC=$?
+ if [[ $PROP_RC -ne 0 ]]; then
+ echo " ✗ PropGatedPublicEndpoint tests failed — see test-results/parallel/prop_gated_public_endpoint.log"
+ else
+ echo " ✓ PropGatedPublicEndpoint tests passed"
+ fi
+ fi
+fi
+RCS+=($PROP_RC)
+
END=$(date +%s)
-ELAPSED=$(( (END - START) / 60 ))
-SEC=$(( (END - START) % 60 ))
+ELAPSED=$(( (SHARDS_END - START) / 60 ))
+SEC=$(( (SHARDS_END - START) % 60 ))
+TOTAL_ELAPSED=$(( (END - START) / 60 ))
+TOTAL_SEC=$(( (END - START) % 60 ))
echo ""
echo "══════════════════════════════════════"
-echo "All ${TOTAL_SHARDS} shards done in ${ELAPSED}m ${SEC}s"
+echo "All ${TOTAL_SHARDS} shards done in ${ELAPSED}m ${SEC}s (whole run ${TOTAL_ELAPSED}m ${TOTAL_SEC}s incl. the prop-gated step)"
echo ""
for (( n=1; n<=TOTAL_SHARDS; n++ )); do
diff --git a/scripts/OpenAPI31Exporter.scala b/scripts/OpenAPI31Exporter.scala
deleted file mode 100644
index 5f672ed554..0000000000
--- a/scripts/OpenAPI31Exporter.scala
+++ /dev/null
@@ -1,410 +0,0 @@
-#!/usr/bin/env scala
-
-/**
- * OpenAPI 3.1 Exporter for OBP API v6.0.0
- *
- * This script extracts API documentation from the OBP API v6.0.0 codebase
- * and converts it to OpenAPI 3.1 format.
- *
- * Usage:
- * scala OpenAPI31Exporter.scala [output_file]
- *
- * If no output file is specified, it writes to stdout.
- */
-
-import scala.io.Source
-import scala.util.matching.Regex
-import java.io.{File, PrintWriter}
-import scala.collection.mutable.ListBuffer
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
-
-case class ApiEndpoint(
- name: String,
- method: String,
- path: String,
- summary: String,
- description: String,
- requestBody: Option[String],
- responseBody: Option[String],
- errorCodes: List[String],
- tags: List[String],
- roles: List[String] = List.empty
-)
-
-case class JsonSchema(
- name: String,
- properties: Map[String, Any],
- required: List[String] = List.empty,
- description: Option[String] = None
-)
-
-object OpenAPI31Exporter {
-
- def main(args: Array[String]): Unit = {
- val outputFile = if (args.length > 0) Some(args(0)) else None
- val projectRoot = findProjectRoot()
-
- println(s"Extracting API documentation from: $projectRoot")
- val endpoints = extractEndpoints(projectRoot)
- val schemas = extractSchemas(projectRoot)
-
- val openApiYaml = generateOpenAPI31(endpoints, schemas)
-
- outputFile match {
- case Some(file) =>
- val writer = new PrintWriter(new File(file))
- try {
- writer.write(openApiYaml)
- println(s"OpenAPI 3.1 documentation written to: $file")
- } finally {
- writer.close()
- }
- case None =>
- println(openApiYaml)
- }
- }
-
- def findProjectRoot(): String = {
- val currentDir = new File(".")
- val candidates = List(
- "./obp-api/src/main/scala/code/api/v6_0_0",
- "../obp-api/src/main/scala/code/api/v6_0_0",
- "./OBP-API/obp-api/src/main/scala/code/api/v6_0_0"
- )
-
- candidates.find(path => new File(path).exists()) match {
- case Some(path) => new File(path).getParentFile.getParentFile.getParentFile.getParentFile.getParentFile.getAbsolutePath
- case None =>
- throw new RuntimeException("Could not find OBP API project root. Please run from the project directory.")
- }
- }
-
- def extractEndpoints(projectRoot: String): List[ApiEndpoint] = {
- val apiMethodsFile = new File(s"$projectRoot/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala")
- val endpoints = ListBuffer[ApiEndpoint]()
-
- if (!apiMethodsFile.exists()) {
- throw new RuntimeException(s"APIMethods600.scala not found at: ${apiMethodsFile.getAbsolutePath}")
- }
-
- val content = Source.fromFile(apiMethodsFile).getLines().mkString("\n")
-
- // Extract ResourceDoc definitions
- val resourceDocPattern = """staticResourceDocs \+= ResourceDoc\(\s*([^,]+),\s*[^,]+,\s*[^,]+,\s*"([^"]+)",\s*"([^"]+)",\s*"([^"]+)",\s*s?"""([^"]*(?:"[^"]*"[^"]*)*?)""",\s*([^,]+),\s*([^,]+),\s*List\(([^)]*)\),\s*List\(([^)]*)\)(?:,\s*Some\(List\(([^)]*)\)))?\s*\)""".r
-
- resourceDocPattern.findAllMatchIn(content).foreach { m =>
- val endpointName = m.group(1).trim
- val method = m.group(2).trim
- val path = m.group(3).trim
- val summary = m.group(4).trim
- val description = cleanDescription(m.group(5))
- val requestBodyRef = m.group(6).trim
- val responseBodyRef = m.group(7).trim
- val errorCodes = parseList(m.group(8))
- val tags = parseList(m.group(9))
- val roles = if (m.group(10) != null) parseList(m.group(10)) else List.empty
-
- endpoints += ApiEndpoint(
- name = endpointName,
- method = method,
- path = path,
- summary = summary,
- description = description,
- requestBody = if (requestBodyRef != "EmptyBody") Some(requestBodyRef) else None,
- responseBody = Some(responseBodyRef),
- errorCodes = errorCodes,
- tags = tags,
- roles = roles
- )
- }
-
- endpoints.toList
- }
-
- def extractSchemas(projectRoot: String): List[JsonSchema] = {
- val jsonFactoryFile = new File(s"$projectRoot/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala")
- val schemas = ListBuffer[JsonSchema]()
-
- if (!jsonFactoryFile.exists()) {
- println(s"Warning: JSONFactory6.0.0.scala not found at: ${jsonFactoryFile.getAbsolutePath}")
- return schemas.toList
- }
-
- val content = Source.fromFile(jsonFactoryFile).getLines().mkString("\n")
-
- // Extract case class definitions
- val caseClassPattern = """case class ([A-Za-z0-9_]+)\(\s*(.*?)\s*\)""".r
-
- caseClassPattern.findAllMatchIn(content).foreach { m =>
- val className = m.group(1)
- val fieldsStr = m.group(2)
-
- val properties = parseFields(fieldsStr)
- val required = properties.filter(_._2.asInstanceOf[Map[String, Any]].get("nullable").isEmpty).keys.toList
-
- schemas += JsonSchema(
- name = className,
- properties = properties,
- required = required,
- description = Some(s"Schema for $className")
- )
- }
-
- schemas.toList
- }
-
- def parseFields(fieldsStr: String): Map[String, Any] = {
- val properties = scala.collection.mutable.Map[String, Any]()
-
- if (fieldsStr.trim.nonEmpty) {
- val fieldPattern = """([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([^,]+)""".r
-
- fieldPattern.findAllMatchIn(fieldsStr).foreach { m =>
- val fieldName = m.group(1).trim
- val fieldType = m.group(2).trim
-
- val (schemaType, nullable) = mapScalaTypeToJsonSchema(fieldType)
-
- val fieldSchema = scala.collection.mutable.Map[String, Any](
- "type" -> schemaType
- )
-
- if (nullable) {
- fieldSchema += "nullable" -> true
- }
-
- if (fieldType.contains("Date")) {
- fieldSchema += "format" -> "date-time"
- }
-
- properties += fieldName -> fieldSchema.toMap
- }
- }
-
- properties.toMap
- }
-
- def mapScalaTypeToJsonSchema(scalaType: String): (String, Boolean) = {
- val cleanType = scalaType.replaceAll("Option\\[(.*)\\]", "$1").trim
- val nullable = scalaType.contains("Option[")
-
- val jsonType = cleanType match {
- case t if t.startsWith("String") => "string"
- case t if t.startsWith("Int") || t.startsWith("Long") => "integer"
- case t if t.startsWith("Double") || t.startsWith("Float") || t.startsWith("BigDecimal") => "number"
- case t if t.startsWith("Boolean") => "boolean"
- case t if t.startsWith("List[") || t.startsWith("Array[") => "array"
- case t if t.contains("Date") => "string"
- case _ => "object"
- }
-
- (jsonType, nullable)
- }
-
- def cleanDescription(desc: String): String = {
- desc.replaceAll("\\|", "")
- .replaceAll("\\$\\{[^}]+\\}", "")
- .replaceAll("\\s+", " ")
- .trim
- }
-
- def parseList(listStr: String): List[String] = {
- if (listStr.trim.isEmpty) List.empty
- else listStr.split(",").map(_.trim.replaceAll("[\"$]", "")).filter(_.nonEmpty).toList
- }
-
- def generateOpenAPI31(endpoints: List[ApiEndpoint], schemas: List[JsonSchema]): String = {
- val timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
-
- val yaml = new StringBuilder()
-
- // OpenAPI header
- yaml.append("openapi: 3.1.0\n")
- yaml.append("\n")
- yaml.append("info:\n")
- yaml.append(" title: Open Bank Project API v6.0.0\n")
- yaml.append(" version: 6.0.0\n")
- yaml.append(" description: |\n")
- yaml.append(" The Open Bank Project API v6.0.0 provides standardized banking APIs.\n")
- yaml.append(" \n")
- yaml.append(" This specification was automatically generated from the OBP API codebase.\n")
- yaml.append(s" Generated on: $timestamp\n")
- yaml.append(" \n")
- yaml.append(" For more information, visit: https://github.com/OpenBankProject/OBP-API\n")
- yaml.append(" contact:\n")
- yaml.append(" name: Open Bank Project\n")
- yaml.append(" url: https://www.openbankproject.com\n")
- yaml.append(" email: contact@tesobe.com\n")
- yaml.append(" license:\n")
- yaml.append(" name: AGPL v3\n")
- yaml.append(" url: https://www.gnu.org/licenses/agpl-3.0.html\n")
- yaml.append("\n")
-
- // Servers
- yaml.append("servers:\n")
- yaml.append(" - url: https://api.openbankproject.com\n")
- yaml.append(" description: Production server\n")
- yaml.append(" - url: https://apisandbox.openbankproject.com\n")
- yaml.append(" description: Sandbox server\n")
- yaml.append("\n")
-
- // Security schemes
- yaml.append("components:\n")
- yaml.append(" securitySchemes:\n")
- yaml.append(" DirectLogin:\n")
- yaml.append(" type: apiKey\n")
- yaml.append(" in: header\n")
- yaml.append(" name: Authorization\n")
- yaml.append(" description: Direct Login token authentication\n")
- yaml.append(" GatewayLogin:\n")
- yaml.append(" type: apiKey\n")
- yaml.append(" in: header\n")
- yaml.append(" name: Authorization\n")
- yaml.append(" description: Gateway Login token authentication\n")
- yaml.append(" OAuth2:\n")
- yaml.append(" type: oauth2\n")
- yaml.append(" flows:\n")
- yaml.append(" authorizationCode:\n")
- yaml.append(" authorizationUrl: /oauth/authorize\n")
- yaml.append(" tokenUrl: /oauth/token\n")
- yaml.append(" scopes: {}\n")
- yaml.append("\n")
-
- // Schemas
- if (schemas.nonEmpty) {
- yaml.append(" schemas:\n")
- schemas.foreach { schema =>
- yaml.append(s" ${schema.name}:\n")
- yaml.append(" type: object\n")
- if (schema.description.isDefined) {
- yaml.append(s" description: ${schema.description.get}\n")
- }
- if (schema.required.nonEmpty) {
- yaml.append(" required:\n")
- schema.required.foreach { field =>
- yaml.append(s" - $field\n")
- }
- }
- if (schema.properties.nonEmpty) {
- yaml.append(" properties:\n")
- schema.properties.foreach { case (name, propSchema) =>
- val props = propSchema.asInstanceOf[Map[String, Any]]
- yaml.append(s" $name:\n")
- yaml.append(s" type: ${props("type")}\n")
- props.get("format").foreach { format =>
- yaml.append(s" format: $format\n")
- }
- props.get("nullable").foreach { _ =>
- yaml.append(" nullable: true\n")
- }
- }
- }
- yaml.append("\n")
- }
- }
-
- // Paths
- yaml.append("paths:\n")
-
- val groupedEndpoints = endpoints.groupBy(_.path)
- groupedEndpoints.toSeq.sortBy(_._1).foreach { case (path, pathEndpoints) =>
- val openApiPath = convertPathToOpenAPI(path)
- yaml.append(s" $openApiPath:\n")
-
- pathEndpoints.sortBy(_.method).foreach { endpoint =>
- val method = endpoint.method.toLowerCase
- yaml.append(s" $method:\n")
- yaml.append(s" summary: ${endpoint.summary}\n")
- yaml.append(s" operationId: ${endpoint.name}\n")
-
- if (endpoint.description.nonEmpty) {
- yaml.append(" description: |\n")
- endpoint.description.split("\n").foreach { line =>
- yaml.append(s" $line\n")
- }
- }
-
- if (endpoint.tags.nonEmpty) {
- yaml.append(" tags:\n")
- endpoint.tags.foreach { tag =>
- yaml.append(s" - ${tag.replaceAll("apiTag", "")}\n")
- }
- }
-
- // Parameters (path parameters)
- val pathParams = extractPathParameters(path)
- if (pathParams.nonEmpty) {
- yaml.append(" parameters:\n")
- pathParams.foreach { param =>
- yaml.append(s" - name: $param\n")
- yaml.append(" in: path\n")
- yaml.append(" required: true\n")
- yaml.append(" schema:\n")
- yaml.append(" type: string\n")
- }
- }
-
- // Request body
- if (endpoint.requestBody.isDefined && method != "get" && method != "delete") {
- yaml.append(" requestBody:\n")
- yaml.append(" required: true\n")
- yaml.append(" content:\n")
- yaml.append(" application/json:\n")
- yaml.append(" schema:\n")
- yaml.append(s" $$ref: '#/components/schemas/${endpoint.requestBody.get}'\n")
- }
-
- // Responses
- yaml.append(" responses:\n")
- yaml.append(" '200':\n")
- yaml.append(" description: Success\n")
- if (endpoint.responseBody.isDefined) {
- yaml.append(" content:\n")
- yaml.append(" application/json:\n")
- yaml.append(" schema:\n")
- yaml.append(s" $$ref: '#/components/schemas/${endpoint.responseBody.get}'\n")
- }
-
- // Error responses
- if (endpoint.errorCodes.nonEmpty) {
- endpoint.errorCodes.filter(_.contains("400")).foreach { _ =>
- yaml.append(" '400':\n")
- yaml.append(" description: Bad Request\n")
- }
- endpoint.errorCodes.filter(_.contains("401")).foreach { _ =>
- yaml.append(" '401':\n")
- yaml.append(" description: Unauthorized\n")
- }
- endpoint.errorCodes.filter(_.contains("404")).foreach { _ =>
- yaml.append(" '404':\n")
- yaml.append(" description: Not Found\n")
- }
- }
-
- // Security
- if (endpoint.roles.nonEmpty || !endpoint.errorCodes.exists(_.contains("AuthenticatedUserIsRequired"))) {
- yaml.append(" security:\n")
- yaml.append(" - DirectLogin: []\n")
- yaml.append(" - GatewayLogin: []\n")
- yaml.append(" - OAuth2: []\n")
- }
-
- yaml.append("\n")
- }
- }
-
- yaml.toString()
- }
-
- def convertPathToOpenAPI(obpPath: String): String = {
- obpPath.replaceAll("([A-Z_]+)", "{$1}")
- .replaceAll("\\{([A-Z_]+)\\}", "{${1.toLowerCase}}")
- .replaceAll("_", "-")
- }
-
- def extractPathParameters(path: String): List[String] = {
- val paramPattern = """([A-Z_]+)""".r
- paramPattern.findAllMatchIn(path).map(_.group(1).toLowerCase.replace("_", "-")).toList
- }
-}
\ No newline at end of file
diff --git a/scripts/check_lift_http4s_resource_doc_parity.py b/scripts/check_lift_http4s_resource_doc_parity.py
index c400cca811..8adf80e600 100755
--- a/scripts/check_lift_http4s_resource_doc_parity.py
+++ b/scripts/check_lift_http4s_resource_doc_parity.py
@@ -2,10 +2,11 @@
"""
check_lift_http4s_resource_doc_parity.py
-For each API version, compare ResourceDoc declarations in the Lift APIMethods*.scala
-file against those in the corresponding Http4s*.scala file. Report fields that
-differ (summary, description, example request body, success response body,
-errors, tags).
+For each API version, compare ResourceDoc declarations from the Lift-era JSON
+baseline (scripts/resource_doc_baseline/lift_resource_docs_vX_Y_Z.json — see
+scripts/resource_doc_baseline/README.md) against those in the corresponding
+live Http4s*.scala file. Report fields that differ (summary, description,
+example request body, success response body, errors, tags).
Read-only. Produces a report to stdout. No files are modified.
@@ -14,19 +15,29 @@
python3 scripts/check_lift_http4s_resource_doc_parity.py v6_0_0 # one version
python3 scripts/check_lift_http4s_resource_doc_parity.py v5_1_0 v6_0_0
python3 scripts/check_lift_http4s_resource_doc_parity.py --field=successResponseBody v6_0_0
+ python3 scripts/check_lift_http4s_resource_doc_parity.py --report-stale-allowlist-entries
-The "Lift file" can be either:
- - an active APIMethodsXYZ.scala (live Lift code, as in v1..v4)
- - a stubbed APIMethodsXYZ.scala where the original Lift code is preserved as
- line comments (as in v5.0.0 / v5.1.0 / v6.0.0). The script strips leading
- `// ` from such files before parsing.
+The Lift-side JSON baseline was exported once (scripts/resource_doc_baseline/export_and_verify.py
+--write) from what used to be the original Lift ResourceDoc text, preserved as
+commented-out lines inside the 12 APIMethodsXYZ.scala files before their
+deletion — see git history for those files. Known, reviewed differences
+between the two sides are recorded in scripts/resource_doc_baseline/parity_allowlist.json
+and do not fail this script; anything not in that allowlist, or whose content
+has drifted since it was allowlisted, does.
+
+The Http4s-side parsing (collect_resourcedocs, uncomment, etc.) is unchanged
+from before this script read JSON — it still reads live Http4s*.scala source,
+using the same string/paren-aware parser this file has always used, because
+that side is still live code.
The 8th/9th positional ResourceDoc fields are exampleRequestBody/successResponseBody
(see APIUtil.scala:1589 case class ResourceDoc). When http4s has `EmptyBody` and
-Lift has a populated case class, that surfaces in the report.
+the Lift baseline has a populated case class, that surfaces in the report.
"""
import argparse
+import hashlib
+import json
import os
import re
import sys
@@ -34,8 +45,20 @@
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
+BASELINE_DIR = REPO_ROOT / "scripts" / "resource_doc_baseline"
+DEFAULT_ALLOWLIST_PATH = BASELINE_DIR / "parity_allowlist.json"
API_ROOT = REPO_ROOT / "obp-api" / "src" / "main" / "scala" / "code" / "api"
+VERSION_RE = re.compile(r"^v\d+_\d+_\d+$")
+
+
+def resolve_inside(path: Path, root: Path, what: str) -> Path:
+ """Resolve a caller-supplied path and require it to stay under root."""
+ resolved = Path(path).resolve()
+ if resolved != root and root not in resolved.parents:
+ sys.exit(f"ERROR: {what} must be inside {root}, got: {resolved}")
+ return resolved
+
# Positional fields in the pre-teardown ResourceDoc(...) signature, which is what
# the commented-out Lift baselines still use — the endpoint partial function was
# the first parameter.
@@ -84,6 +107,24 @@
"authMode",
}
+# Maps CURRENT_POSITIONAL_FIELDS names (Scala-side, camelCase) to the JSON baseline's
+# snake_case keys (scripts/resource_doc_baseline/lift_resource_docs_vX_Y_Z.json). Shared
+# with scripts/resource_doc_baseline/export_and_verify.py, which imports this module
+# rather than redefining the mapping — the two must stay in lockstep, or the export
+# and this script's read-back would silently disagree on field names.
+FIELD_JSON_KEYS = {
+ "partialFunctionName": "partial_function_name_raw",
+ "requestVerb": "request_verb",
+ "requestUrl": "request_url",
+ "summary": "summary",
+ "description": "description",
+ "exampleRequestBody": "example_request_body",
+ "successResponseBody": "success_response_body",
+ "errorResponseBodies": "error_response_bodies",
+ "tags": "tags",
+}
+JSON_KEY_TO_FIELD = {v: k for k, v in FIELD_JSON_KEYS.items()}
+
def uncomment(source: str) -> str:
"""Strip leading `//` (with optional single space) from every line.
@@ -400,7 +441,19 @@ def pick(files, prefix):
return pick(api_methods, "APIMethods"), pick(http4s, "Http4s")
-def collect_resourcedocs(path: Path):
+def collect_resourcedocs_with_stats(path: Path):
+ """Parse a file's ResourceDoc registrations.
+
+ Returns (docs, stats) where stats records what was seen but NOT stored:
+ blocks — registrations found after comment stripping
+ unparsed — blocks with no extractable partialFunctionName
+ duplicates — blocks whose endpoint name was already taken (first wins)
+
+ Callers that are about to treat `docs` as a faithful copy of the file (the
+ baseline export, which then authorises deleting it) need those counts: a
+ digest over `docs` alone cannot reveal a registration that never made it
+ into `docs` in the first place.
+ """
source = path.read_text(encoding="utf-8")
active = re.search(r"^\s*(?:static)?[rR]esourceDocs\s*\+=\s*ResourceDoc\s*\(", source, re.M)
commented = re.search(r"^\s*//\s*(?:static)?[rR]esourceDocs\s*\+=\s*ResourceDoc\s*\(", source, re.M)
@@ -408,18 +461,115 @@ def collect_resourcedocs(path: Path):
source = uncomment(source)
source = strip_inline_comments(source)
docs = OrderedDict()
+ stats = {"blocks": 0, "unparsed": 0, "duplicates": 0, "duplicate_names": []}
for _, _, body in find_resourcedoc_blocks(source):
+ stats["blocks"] += 1
args = parse_resourcedoc(body)
if "partialFunctionName" not in args:
+ stats["unparsed"] += 1
continue
name = endpoint_name(args["partialFunctionName"])
# Key by endpoint name only — URL/verb get compared as fields so
# intentional renames during migration show up as field diffs rather
# than "missing" entries.
- docs.setdefault(name, args)
+ if name in docs:
+ stats["duplicates"] += 1
+ stats["duplicate_names"].append(name)
+ continue
+ docs[name] = args
+ return docs, stats
+
+
+def collect_resourcedocs(path: Path):
+ docs, _ = collect_resourcedocs_with_stats(path)
return docs
+def find_http4s_path(version: str):
+ """Locate the canonical Http4sNNN.scala for a version (no longer paired
+ against an APIMethods*.scala file — that side now comes from the JSON
+ baseline via load_baseline_docs). Same "prefer the canonical short name"
+ ranking find_pair_for_version used to apply to both sides.
+ """
+ vdir = API_ROOT / version
+ if not vdir.is_dir():
+ return None
+ candidates = list(vdir.glob("Http4s*.scala"))
+ if not candidates:
+ return None
+ ranked = sorted(
+ candidates,
+ key=lambda p: (0 if re.match(r"^Http4s\d+\.scala$", p.name) else 1, len(p.name)),
+ )
+ return ranked[0]
+
+
+def load_baseline_docs(version: str):
+ """Read scripts/resource_doc_baseline/lift_resource_docs_vX_Y_Z.json and
+ return the same OrderedDict[name -> args] shape collect_resourcedocs()
+ produces from .scala source, using the ORIGINAL Scala field names
+ (requestVerb, requestUrl, ...) via JSON_KEY_TO_FIELD, so every function
+ below this point (normalize, normalize_list, the diff loop) can treat
+ JSON-sourced and .scala-sourced docs identically. Returns None if no
+ baseline file exists for this version.
+ """
+ if not VERSION_RE.match(version):
+ sys.exit(f"ERROR: not a valid version token: {version!r} (expected e.g. v6_0_0)")
+ path = BASELINE_DIR / f"lift_resource_docs_{version}.json"
+ if not path.exists():
+ return None
+ data = json.loads(path.read_text(encoding="utf-8"))
+ docs = OrderedDict()
+ for name, entry in data.get("endpoints", {}).items():
+ args = OrderedDict()
+ for json_key, value in entry.items():
+ if json_key == "extra_named_args":
+ for k, v in value.items():
+ args[k] = v
+ continue
+ field = JSON_KEY_TO_FIELD.get(json_key)
+ if field:
+ args[field] = value
+ docs[name] = args
+ return docs
+
+
+def load_allowlist(path: Path):
+ path = resolve_inside(path, REPO_ROOT, "--allowlist")
+ if not path.exists():
+ return {"rename_pairs": [], "only_in_lift": [], "only_in_http4s": [], "field_mismatches": []}
+ data = json.loads(path.read_text(encoding="utf-8"))
+ data.setdefault("rename_pairs", [])
+ data.setdefault("only_in_lift", [])
+ data.setdefault("only_in_http4s", [])
+ data.setdefault("field_mismatches", [])
+ return data
+
+
+def identity_digest(verb: str, url: str) -> str:
+ """Digest an endpoint's (verb, url) identity for only_in_lift/only_in_http4s
+ allowlist entries — bound to VALUE, not name: if the endpoint's verb/url
+ changes after being allowlisted, this digest changes and the entry stops
+ matching (drift), rather than silently continuing to suppress a now-different
+ endpoint that happens to share the old name.
+ """
+ key = f"{normalize(verb)}|{normalize(url)}"
+ return hashlib.sha256(key.encode("utf-8")).hexdigest()
+
+
+def field_digest(value, field: str) -> str:
+ """Digest one field's normalized value for field_mismatches allowlist entries.
+ Uses the same normalize()/normalize_list() the diff loop itself uses for
+ equality, so pure reformatting never counts as drift — but any real content
+ change does.
+ """
+ if field in ("errorResponseBodies", "tags"):
+ norm = normalize_list(value)
+ else:
+ norm = normalize(value)
+ return hashlib.sha256((norm or "").encode("utf-8")).hexdigest()
+
+
def main():
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("versions", nargs="*", help="Versions like v6_0_0 (omit = all auto-discovered)")
@@ -429,60 +579,132 @@ def main():
help="Just list endpoints; do not print diffs")
ap.add_argument("--verbose-bodies", action="store_true",
help="Print full lift/http4s field values (default: truncated to 200 chars)")
+ ap.add_argument("--allowlist", type=Path, default=DEFAULT_ALLOWLIST_PATH,
+ help=f"Path to the allowlist JSON (default: {DEFAULT_ALLOWLIST_PATH})")
+ ap.add_argument("--report-stale-allowlist-entries", action="store_true",
+ help="List allowlist entries that matched nothing this run "
+ "(informational; does not affect exit code)")
args = ap.parse_args()
fields = args.field or DEFAULT_DIFF_FIELDS
truncate_len = 100000 if args.verbose_bodies else 200
+ allowlist = load_allowlist(args.allowlist)
+ used = {"rename_pairs": set(), "only_in_lift": set(), "only_in_http4s": set(), "field_mismatches": set()}
versions = args.versions
if not versions:
versions = sorted(
d.name for d in API_ROOT.iterdir()
- if d.is_dir() and re.match(r"^v\d+_\d+_\d+$", d.name)
+ if d.is_dir() and VERSION_RE.match(d.name)
)
total_endpoints = 0
- total_mismatches = 0
- only_in_lift = []
+ total_mismatches = 0 # unallowlisted or drifted field mismatches
+ total_allowlisted_mismatches = 0
+ only_in_lift = [] # unallowlisted or drifted
only_in_http4s = []
+ allowlisted_only_lift_count = 0
+ allowlisted_only_http4s_count = 0
per_field_counts = {f: 0 for f in fields}
per_version_summary = []
for v in versions:
- vdir = API_ROOT / v
- pair = find_pair_for_version(vdir)
- if not pair:
- print(f"[{v}] no APIMethods/Http4s pair found — skipping", file=sys.stderr)
+ lift_docs = load_baseline_docs(v)
+ if lift_docs is None:
+ print(f"[{v}] no JSON baseline found "
+ f"(scripts/resource_doc_baseline/lift_resource_docs_{v}.json) — skipping", file=sys.stderr)
+ continue
+ http_path = find_http4s_path(v)
+ if http_path is None:
+ print(f"[{v}] no Http4s*.scala found — skipping", file=sys.stderr)
continue
- lift_path, http_path = pair
- lift_docs = collect_resourcedocs(lift_path)
http_docs = collect_resourcedocs(http_path)
+ # Resolve rename pairs first: fold a known Lift-name/http4s-name pair into
+ # one shared entry (keyed by the http4s name) before computing only-lift/
+ # only-http4s, so an intentional rename never shows up as "missing" on
+ # either side. If the pair's (verb, url) identity has drifted since it was
+ # allowlisted, leave it unresolved — it falls through to the ordinary
+ # only-lift/only-http4s path below and (absent a separate allowlist entry)
+ # correctly shows up as a new, unallowlisted difference.
+ for idx, p in enumerate(allowlist["rename_pairs"]):
+ if p.get("version") != v:
+ continue
+ lift_name, http4s_name = p.get("lift_name"), p.get("http4s_name")
+ if lift_name in lift_docs and http4s_name in lift_docs:
+ # Remapping would overwrite a real Lift entry and drop it from the
+ # comparison entirely, so any drift inside it would pass unseen.
+ print(f" ✗ CONFLICTING rename pair {lift_name} -> {http4s_name} ({v}): "
+ f"both names exist on the Lift side; refusing to remap", file=sys.stderr)
+ elif lift_name in lift_docs and http4s_name in http_docs:
+ lift_entry = lift_docs[lift_name]
+ http_entry = http_docs[http4s_name]
+ lift_id = identity_digest(lift_entry.get("requestVerb", ""), lift_entry.get("requestUrl", ""))
+ http_id = identity_digest(http_entry.get("requestVerb", ""), http_entry.get("requestUrl", ""))
+ if lift_id == p.get("lift_identity_digest") and http_id == p.get("http4s_identity_digest"):
+ lift_docs[http4s_name] = lift_docs.pop(lift_name)
+ used["rename_pairs"].add(idx)
+ else:
+ print(f" ✗ DRIFTED rename pair {lift_name} -> {http4s_name} ({v}): "
+ f"identity changed since allowlisted, treating as a normal miss", file=sys.stderr)
+
lift_keys = set(lift_docs.keys())
http_keys = set(http_docs.keys())
print(f"\n=== {v} ===")
- print(f" lift: {lift_path.relative_to(REPO_ROOT)} ({len(lift_docs)} docs)")
+ print(f" lift: scripts/resource_doc_baseline/lift_resource_docs_{v}.json ({len(lift_docs)} docs)")
print(f" http4s: {http_path.relative_to(REPO_ROOT)} ({len(http_docs)} docs)")
- miss_http = sorted(lift_keys - http_keys)
- miss_lift = sorted(http_keys - lift_keys)
- if miss_http:
- print(f" ⚠ {len(miss_http)} endpoint(s) in Lift but NOT in Http4s:")
- for name in miss_http:
- d = lift_docs[name]
+ def partition_only(names, docs, allowlist_key):
+ """Split names present on only one side into (new, allowlisted),
+ checking each candidate against the matching allowlist category by
+ (version, endpoint) and confirming its identity digest still matches."""
+ new_ones, allowed_ones = [], []
+ for name in names:
+ d = docs[name]
verb = d.get("requestVerb", "").strip().strip('"')
url = d.get("requestUrl", "").strip().strip('"')
+ digest = identity_digest(d.get("requestVerb", ""), d.get("requestUrl", ""))
+ match_idx, match_entry = None, None
+ for idx, e in enumerate(allowlist[allowlist_key]):
+ if e.get("version") == v and e.get("endpoint") == name:
+ match_idx, match_entry = idx, e
+ break
+ if match_entry is not None and match_entry.get("identity_digest") == digest:
+ used[allowlist_key].add(match_idx)
+ allowed_ones.append((verb, url, name))
+ else:
+ if match_entry is not None:
+ print(f" ✗ DRIFTED {verb:6} {url} ({name}) [{v}] — "
+ f"identity changed since allowlisted", file=sys.stderr)
+ new_ones.append((verb, url, name))
+ return new_ones, allowed_ones
+
+ miss_http = sorted(lift_keys - http_keys) # only in lift
+ miss_lift = sorted(http_keys - lift_keys) # only in http4s
+ new_only_lift, allowed_only_lift = partition_only(miss_http, lift_docs, "only_in_lift")
+ new_only_http4s, allowed_only_http4s = partition_only(miss_lift, http_docs, "only_in_http4s")
+ only_in_lift.extend((v, name) for _, _, name in new_only_lift)
+ only_in_http4s.extend((v, name) for _, _, name in new_only_http4s)
+ allowlisted_only_lift_count += len(allowed_only_lift)
+ allowlisted_only_http4s_count += len(allowed_only_http4s)
+
+ if new_only_lift:
+ print(f" ⚠ {len(new_only_lift)} endpoint(s) in Lift but NOT in Http4s (not allowlisted):")
+ for verb, url, name in new_only_lift:
print(f" - {verb:6} {url} ({name})")
- only_in_lift.extend((v, name) for name in miss_http)
- if miss_lift:
- print(f" ⚠ {len(miss_lift)} endpoint(s) in Http4s but NOT in Lift:")
- for name in miss_lift:
- d = http_docs[name]
- verb = d.get("requestVerb", "").strip().strip('"')
- url = d.get("requestUrl", "").strip().strip('"')
+ if allowed_only_lift:
+ print(f" ○ {len(allowed_only_lift)} endpoint(s) in Lift but NOT in Http4s (allowlisted):")
+ for verb, url, name in allowed_only_lift:
+ print(f" - {verb:6} {url} ({name})")
+ if new_only_http4s:
+ print(f" ⚠ {len(new_only_http4s)} endpoint(s) in Http4s but NOT in Lift (not allowlisted):")
+ for verb, url, name in new_only_http4s:
+ print(f" - {verb:6} {url} ({name})")
+ if allowed_only_http4s:
+ print(f" ○ {len(allowed_only_http4s)} endpoint(s) in Http4s but NOT in Lift (allowlisted):")
+ for verb, url, name in allowed_only_http4s:
print(f" - {verb:6} {url} ({name})")
- only_in_http4s.extend((v, name) for name in miss_lift)
shared = sorted(lift_keys & http_keys)
version_mismatches = 0
@@ -494,6 +716,7 @@ def main():
l = lift_docs[name]
h = http_docs[name]
diffs = []
+ allowlisted_diffs = []
for f in fields:
lv = l.get(f)
hv = h.get(f)
@@ -501,7 +724,25 @@ def main():
eq = normalize_list(lv) == normalize_list(hv)
else:
eq = normalize(lv) == normalize(hv)
- if not eq:
+ if eq:
+ continue
+ lift_dig = field_digest(lv, f)
+ http_dig = field_digest(hv, f)
+ match_idx, match_entry = None, None
+ for idx, e in enumerate(allowlist["field_mismatches"]):
+ if e.get("version") == v and e.get("endpoint") == name and e.get("field") == f:
+ match_idx, match_entry = idx, e
+ break
+ if (match_entry is not None
+ and match_entry.get("lift_digest") == lift_dig
+ and match_entry.get("http4s_digest") == http_dig):
+ used["field_mismatches"].add(match_idx)
+ allowlisted_diffs.append((f, lv, hv))
+ total_allowlisted_mismatches += 1
+ else:
+ if match_entry is not None:
+ print(f" ✗ DRIFTED allowlisted field mismatch {name}.{f} ({v}) — "
+ f"value changed since allowlisted", file=sys.stderr)
diffs.append((f, lv, hv))
per_field_counts[f] += 1
if diffs:
@@ -509,25 +750,49 @@ def main():
total_mismatches += 1
verb = h.get("requestVerb", l.get("requestVerb", "")).strip().strip('"')
url = h.get("requestUrl", l.get("requestUrl", "")).strip().strip('"')
- print(f"\n ✗ {verb:6} {url} ({name})")
+ print(f"\n ✗ {verb:6} {url} ({name}) [not allowlisted]")
for fname, lv, hv in diffs:
print(f" [{fname}]")
print(f" lift: {short(lv, truncate_len)}")
print(f" http4s: {short(hv, truncate_len)}")
- if version_mismatches == 0 and not miss_http and not miss_lift:
- print(" ✓ all shared endpoints match")
+ if allowlisted_diffs and args.verbose_bodies:
+ verb = h.get("requestVerb", l.get("requestVerb", "")).strip().strip('"')
+ url = h.get("requestUrl", l.get("requestUrl", "")).strip().strip('"')
+ print(f"\n ○ {verb:6} {url} ({name}) [allowlisted]")
+ for fname, lv, hv in allowlisted_diffs:
+ print(f" [{fname}]")
+ print(f" lift: {short(lv, truncate_len)}")
+ print(f" http4s: {short(hv, truncate_len)}")
+ if version_mismatches == 0 and not new_only_lift and not new_only_http4s:
+ print(" ✓ all shared endpoints match (or all differences are allowlisted)")
per_version_summary.append((v, version_endpoints, version_mismatches,
- len(miss_http), len(miss_lift)))
+ len(new_only_lift), len(new_only_http4s)))
print("\n=== SUMMARY ===")
print(f"{'version':10} {'shared':>8} {'mismatch':>10} {'only-lift':>10} {'only-http4s':>12}")
for v, sh, mm, ml, mh in per_version_summary:
print(f"{v:10} {sh:>8} {mm:>10} {ml:>10} {mh:>12}")
print(f"\nTotal endpoints compared: {total_endpoints}")
- print(f"Total mismatches: {total_mismatches}")
- print(f"Per-field counts:")
+ print(f"Total mismatches (unallowlisted or drifted): {total_mismatches}")
+ print(f"Total mismatches (allowlisted, informational): {total_allowlisted_mismatches}")
+ print(f"Per-field counts (unallowlisted or drifted):")
for f, c in per_field_counts.items():
print(f" {f:25} {c}")
+ print(f"only-in-lift (unallowlisted or drifted): {len(only_in_lift)} "
+ f"(allowlisted: {allowlisted_only_lift_count})")
+ print(f"only-in-http4s (unallowlisted or drifted): {len(only_in_http4s)} "
+ f"(allowlisted: {allowlisted_only_http4s_count})")
+
+ if args.report_stale_allowlist_entries:
+ print("\n=== STALE ALLOWLIST ENTRIES (matched nothing this run) ===")
+ stale_found = False
+ for category in ("rename_pairs", "only_in_lift", "only_in_http4s", "field_mismatches"):
+ for idx, entry in enumerate(allowlist[category]):
+ if idx not in used[category]:
+ stale_found = True
+ print(f" [{category}] {json.dumps(entry, sort_keys=True)}")
+ if not stale_found:
+ print(" (none)")
return 0 if total_mismatches == 0 and not only_in_lift and not only_in_http4s else 1
diff --git a/scripts/count_v7_endpoints.py b/scripts/count_v7_endpoints.py
index 6d361e1178..9c019f9bf7 100644
--- a/scripts/count_v7_endpoints.py
+++ b/scripts/count_v7_endpoints.py
@@ -7,17 +7,19 @@
Inputs are derived from source — no hardcoded data tables:
* Version files are discovered by globbing obp-api/src/main/scala/code/api/v*/
for Http4s{NNN}.scala. All registrations live in Http4s files now — the
- older Lift APIMethods*.scala files have been emptied/commented out.
- * excludeEndpoints lists are extracted from each version's OBPAPI{a}_{b}_{c}.scala
- (or OBPAPI{a}.{b}.{c}.scala for v1.2.1) — and from Http4s700.scala for v7
- which has no OBPAPI counterpart.
-
-Aggregation chain (matches the runtime code in each OBPAPI{a}_{b}_{c}.scala):
- OBPAPI1_2_1.allResourceDocs = Http4s121.resourceDocs (chain root)
- OBPAPI{N}.allResourceDocs = collectResourceDocs(OBPAPI{N-1}, Http4s{N})
- .filterNot(excludeEndpoints if any)
- Http4s700.allResourceDocs = collectResourceDocs(OBPAPI6_0_0, Http4s700)
- .filterNot(v7 excludeEndpoints — currently Nil)
+ older Lift APIMethods*.scala files have been deleted (their historical
+ ResourceDoc text lives on in scripts/resource_doc_baseline/, see that
+ directory's README).
+ * excludeEndpoints lists are extracted from Http4sResourceDocAggregation.scala
+ (as excludeEndpointsV{nnn}) — and from Http4s700.scala for v7, which keeps
+ its own list.
+
+Aggregation chain (matches the runtime code in Http4sResourceDocAggregation):
+ v121 = Http4s121.resourceDocs (chain root)
+ v{N} = collectResourceDocs(v{N-1}, Http4s{N})
+ .filterNot(excludeEndpointsV{N} if any)
+ Http4s700.allResourceDocs = collectResourceDocs(v600, Http4s700)
+ .filterNot(v7 excludeEndpoints — currently Nil)
collectResourceDocs: concat, stable sort by version descending, dedup by (url, verb).
filterNot: drop docs whose partialFunctionName is in the excluded-names set.
@@ -41,7 +43,7 @@
REG_START = re.compile(r"^\s*(?:static)?[Rr]esourceDocs\s*\+=\s*ResourceDoc\s*\(")
ANY_REG_REF = re.compile(r"\w*[Rr]esourceDocs\s*\+=\s*ResourceDoc\b")
NAMEOF_RE = re.compile(r"nameOf\s*\(\s*[\w.]*?(\w+)\s*\)")
-EXCLUDE_DEF_RE = re.compile(r"(?:lazy\s+)?val\s+excludeEndpoints\b[^=]*=")
+EXCLUDE_DEF_RE = re.compile(r"(?:lazy\s+)?val\s+excludeEndpoints(?PV\d{3})?\b[^=]*=")
HTTP_VERBS = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
@@ -63,8 +65,8 @@ def discover_version_files() -> list[tuple[tuple, Path]]:
"""Find every v*/ directory and resolve its Http4s{NNN}.scala source file.
Every version's contribution to the aggregation chain lives in its
- Http4s{NNN}.scala (the older Lift APIMethods*.scala files have been
- commented out and no longer carry registrations).
+ Http4s{NNN}.scala (the older Lift APIMethods*.scala files that used to
+ carry registrations have been deleted).
"""
found = []
for entry in sorted(SRC.iterdir()):
@@ -86,34 +88,41 @@ def discover_version_files() -> list[tuple[tuple, Path]]:
return found
-def find_obpapi_file(version: tuple) -> Path | None:
+AGGREGATION_FILE = SRC / "util" / "http4s" / "Http4sResourceDocAggregation.scala"
+
+
+def find_exclude_source(version: tuple) -> Path | None:
"""Locate the file that owns this version's excludeEndpoints list.
- Most versions: OBPAPI{a}_{b}_{c}.scala. v1.2.1 is an outlier
- (OBPAPI1.2.1.scala with dots). v7 has no OBPAPI counterpart — its
- excludeEndpoints lives in Http4s700.scala.
+ The v1.2.1-v6.0.0 lists live together in Http4sResourceDocAggregation.scala
+ as excludeEndpointsV{nnn} (they moved there when the OBPAPI* aggregator
+ objects were deleted). v7.0.0 keeps its own `excludeEndpoints` in
+ Http4s700.scala.
"""
a, b, c = version
- vdir = SRC / f"v{a}_{b}_{c}"
- for candidate in (
- vdir / f"OBPAPI{a}_{b}_{c}.scala",
- vdir / f"OBPAPI{a}.{b}.{c}.scala",
- vdir / f"Http4s{a}{b}{c}.scala",
- ):
- if candidate.is_file():
- return candidate
- return None
+ own = SRC / f"v{a}_{b}_{c}" / f"Http4s{a}{b}{c}.scala"
+ if own.is_file() and EXCLUDE_DEF_RE.search(own.read_text(encoding="utf-8")):
+ return own
+ return AGGREGATION_FILE if AGGREGATION_FILE.is_file() else None
# -- excludeEndpoints extraction ---------------------------------------
-def extract_excludes(path: Path) -> set[str]:
- """Pull names from `(lazy )?val excludeEndpoints = nameOf(...) :: ... :: Nil`.
+def extract_excludes(path: Path, version: tuple) -> set[str]:
+ """Pull names from `(lazy )?val excludeEndpoints[V{nnn}] = nameOf(...) :: ... :: Nil`.
- Returns the empty set if the val is absent (e.g. v3.0.0, v5.0.0).
+ One file can hold several versions' lists (Http4sResourceDocAggregation), so the
+ val is matched by its V{nnn} suffix; an unsuffixed name is the file's own list.
+ Returns the empty set if there is no such val (e.g. v3.0.0, v5.0.0).
"""
+ want = "V" + "".join(str(p) for p in version)
lines = path.read_text(encoding="utf-8").splitlines()
- start = next((i for i, line in enumerate(lines) if EXCLUDE_DEF_RE.search(line)), None)
+ start = None
+ for i, line in enumerate(lines):
+ m = EXCLUDE_DEF_RE.search(line)
+ if m and (m.group("suffix") or want) == want:
+ start = i
+ break
if start is None:
return set()
@@ -213,13 +222,29 @@ def parse_file(path: Path, version: tuple) -> tuple[list[Doc], set[int]]:
chunk = chunk[chunk.index("ResourceDoc") + len("ResourceDoc"):]
chunk = chunk[chunk.index("(") + 1:]
args = split_top_level_args(chunk, want=5)
- if len(args) < 5:
+ if len(args) < 4:
+ print(f" WARN: incomplete args at {path.name}:{idx + 1}", file=sys.stderr)
+ continue
+ # Detect which ResourceDoc constructor signature this call uses: the Lift
+ # teardown removed the leading `partialFunction` parameter, so a
+ # pre-teardown call (name/verb/url at args[2]/[3]/[4]) and a current one
+ # (args[1]/[2]/[3], no leading partialFunction) put every field at a
+ # different offset. Same detection check_lift_http4s_resource_doc_parity.py
+ # uses for its own POSITIONAL_FIELDS/CURRENT_POSITIONAL_FIELDS split —
+ # every current Http4sXYZ.scala uses the second form, which the previous,
+ # hardcoded-to-the-first-form version of this function silently matched
+ # zero endpoints against.
+ if strip_str_literal(args[2]).upper() in HTTP_VERBS:
+ name_idx, verb_idx, url_idx = 1, 2, 3
+ else:
+ name_idx, verb_idx, url_idx = 2, 3, 4
+ if len(args) <= url_idx:
print(f" WARN: incomplete args at {path.name}:{idx + 1}", file=sys.stderr)
continue
- m = NAMEOF_RE.search(args[2])
- func = m.group(1) if m else strip_str_literal(args[2])
- verb = strip_str_literal(args[3]).upper()
- url = strip_str_literal(args[4])
+ m = NAMEOF_RE.search(args[name_idx])
+ func = m.group(1) if m else strip_str_literal(args[name_idx])
+ verb = strip_str_literal(args[verb_idx]).upper()
+ url = strip_str_literal(args[url_idx])
if verb not in HTTP_VERBS:
print(f" WARN: unexpected verb {verb!r} at {path.name}:{idx + 1}",
file=sys.stderr)
@@ -272,7 +297,7 @@ def collect(*buckets: list[Doc]) -> list[Doc]:
def main() -> None:
version_files = discover_version_files()
if not version_files:
- sys.exit("ERROR: no v*/Http4s*.scala or APIMethods*.scala files found")
+ sys.exit("ERROR: no v*/Http4s*.scala files found")
by_version: dict[tuple, list[Doc]] = {}
self_check_warnings: list[str] = []
@@ -289,17 +314,17 @@ def main() -> None:
excludes: dict[tuple, set[str]] = {}
print("Extracting excludeEndpoints lists from source:")
for version, _ in version_files:
- owner = find_obpapi_file(version)
+ owner = find_exclude_source(version)
if owner is None:
continue
- ex = extract_excludes(owner)
+ ex = extract_excludes(owner, version)
if ex:
excludes[version] = ex
print(f" v{'.'.join(map(str, version))}: "
f"{len(ex)} excludes ({owner.relative_to(REPO)})")
print()
- # Chain root: OBPAPI1_2_1.allResourceDocs = Http4s121.resourceDocs (no concat).
+ # Chain root: v121 = Http4s121.resourceDocs (no concat).
# Every later version: collectResourceDocs(prev, this) [.filterNot(excludes)].
versions_asc = sorted(by_version.keys())
if not versions_asc:
diff --git a/scripts/rehydrate_resource_docs.py b/scripts/rehydrate_resource_docs.py
index ec6ae15ebb..2266cbece0 100755
--- a/scripts/rehydrate_resource_docs.py
+++ b/scripts/rehydrate_resource_docs.py
@@ -5,19 +5,23 @@
Tooling used during the v6.0.0 (and friends) liftweb → http4s migration to
rehydrate `ResourceDoc` registrations whose request/response example bodies
-and descriptions were dropped during the port. The script reads the
-commented-out liftweb predecessor blocks in `APIMethodsXYZ.scala`, parses
-the positional args of each `staticResourceDocs += ResourceDoc(...)` block,
-and writes the descriptions + request + response example bodies into the
-matching `resourceDocs += ResourceDoc(...)` registrations in
-`Http4sXYZ.scala` (matched by `nameOf()`).
+and descriptions were dropped during the port. The script reads the Lift-era
+predecessor data — originally commented-out blocks in `APIMethodsXYZ.scala`,
+now in the JSON baseline at `scripts/resource_doc_baseline/lift_resource_docs_vX_Y_Z.json`
+(see that directory's README) since those `.scala` files were deleted once
+the baseline was verified to reproduce them losslessly — and writes the
+descriptions + request + response example bodies into the matching
+`resourceDocs += ResourceDoc(...)` registrations in `Http4sXYZ.scala`
+(matched by `nameOf()`).
Two subcommands are provided:
- lift Lift description (arg 7), request body (arg 8) and response
- body (arg 9) from each commented liftweb predecessor into the
- matching http4s registration. Idempotent; only patches an
- entry when at least one of the three differs.
+ lift Lift description, exampleRequestBody and successResponseBody
+ from the JSON baseline into the matching http4s registration.
+ Idempotent; only patches an entry when at least one of the
+ three differs. The version (and so which baseline file to
+ read) is derived from --http4s's parent directory name
+ (e.g. .../v5_1_0/Http4s510.scala -> v5_1_0).
split-init Split top-level `resourceDocs += ResourceDoc(...)` statements
inside `object Implementations*` into batched
@@ -25,14 +29,14 @@
object's `` stays under the JVM's 64KB-per-method limit.
Only needed once per Http4sXYZ.scala when post-lift ``
exceeds the bytecode limit (in practice: Http4s600.scala).
+ Doesn't touch the JSON baseline at all — Http4s-file-only.
Usage
-----
# Rehydrate v5.1.0 endpoints (then rebuild with mvn).
python3 scripts/rehydrate_resource_docs.py lift \
- --api-methods obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala \
- --http4s obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala
+ --http4s obp-api/src/main/scala/code/api/v5_1_0/Http4s510.scala
# After rehydrating v6.0.0, the object init blew past 64KB. Split it.
python3 scripts/rehydrate_resource_docs.py split-init \
@@ -83,6 +87,10 @@
import sys
from pathlib import Path
+SCRIPT_DIR = Path(__file__).resolve().parent
+sys.path.insert(0, str(SCRIPT_DIR))
+import check_lift_http4s_resource_doc_parity as parity # noqa: E402
+
# ─────────────────────────────────────────────────────────────────────────
# Scala-aware top-level argument splitter
@@ -250,56 +258,37 @@ def split_top_level(text: str) -> list[str]:
# ─────────────────────────────────────────────────────────────────────────
-# Liftweb predecessor extraction (commented `staticResourceDocs += …` blocks)
+# Lift-era predecessor extraction (scripts/resource_doc_baseline JSON)
# ─────────────────────────────────────────────────────────────────────────
-def collect_liftweb_full(source: str) -> dict[str, tuple[str, str, str]]:
- """Walk source; return { endpointName -> (description, req, resp) } for
- every commented-out `staticResourceDocs += ResourceDoc(...)` block."""
- out: dict[str, tuple[str, str, str]] = {}
- lines = source.splitlines()
- n = len(lines)
- i = 0
- while i < n:
- line = lines[i]
- stripped = line.lstrip()
- if stripped.startswith("//") and "resourceDocs += ResourceDoc(" in stripped:
- depth = 0
- collected: list[str] = []
- end = i
- for j in range(i, n):
- cleaned = lines[j].lstrip()
- if not cleaned.startswith("//"):
- break
- content = cleaned[2:]
- if content.startswith(" "):
- content = content[1:]
- collected.append(content)
- depth += content.count("(") - content.count(")")
- if depth == 0 and "(" in "".join(collected):
- end = j
- break
- else:
- end = n - 1
- block = "\n".join(collected)
- open_idx = block.find("(")
- close_idx = block.rfind(")")
- if open_idx >= 0 and close_idx > open_idx:
- inner = block[open_idx + 1 : close_idx]
- try:
- args = split_top_level(inner)
- except Exception:
- args = []
- if len(args) >= 9:
- name = args[0].strip()
- desc = args[6].strip()
- req = args[7].strip()
- resp = args[8].strip()
- out[name] = (desc, req, resp)
- i = end + 1
- else:
- i += 1
+def version_from_http4s_path(http4s: Path) -> str:
+ """.../v5_1_0/Http4s510.scala -> "v5_1_0" (the baseline filename suffix)."""
+ version = http4s.resolve().parent.name
+ if not parity.VERSION_RE.match(version):
+ raise ValueError(
+ f"couldn't derive a version like v5_1_0 from {http4s}'s parent "
+ f"directory ({version!r}); pass a canonical Http4sXYZ.scala path"
+ )
+ return version
+
+
+def collect_baseline_full(version: str) -> dict:
+ """{ endpointName -> (description, exampleRequestBody, successResponseBody) }
+ for every endpoint in scripts/resource_doc_baseline/lift_resource_docs_.json.
+ Same shape collect_liftweb_full() used to return when it read this data
+ straight out of the (now-deleted) commented-out APIMethodsXYZ.scala blocks.
+ """
+ docs = parity.load_baseline_docs(version)
+ if docs is None:
+ raise FileNotFoundError(
+ f"no baseline at {parity.BASELINE_DIR / f'lift_resource_docs_{version}.json'} "
+ f"— see scripts/resource_doc_baseline/README.md"
+ )
+ out = {}
+ for name, args in docs.items():
+ if "description" in args and "exampleRequestBody" in args and "successResponseBody" in args:
+ out[name] = (args["description"], args["exampleRequestBody"], args["successResponseBody"])
return out
@@ -308,6 +297,46 @@ def collect_liftweb_full(source: str) -> dict[str, tuple[str, str, str]]:
# ─────────────────────────────────────────────────────────────────────────
+def detect_positional_fields(args: list):
+ """Return the field-name list matching THIS call's ResourceDoc signature,
+ or None when neither shape is recognisable.
+
+ The Lift teardown removed the leading `partialFunction` parameter, so a
+ pre-teardown call (11 positional fields, verb literal at index 3) and a
+ current one (10 fields, verb literal at index 2) put every field at a
+ different offset. The verb literal is the discriminator, so exactly one of
+ index 2 and index 3 must hold one; anything else (neither, or both) means
+ the call does not have a shape this tool understands.
+
+ Returning None rather than defaulting matters because the caller writes the
+ file back: guessing wrong shifts every field by one and would splice the
+ description into the summary slot. Reuses parity's
+ POSITIONAL_FIELDS/CURRENT_POSITIONAL_FIELDS/HTTP_VERB_LITERALS rather than
+ a second hardcoded guess that can drift out of sync with them.
+ """
+ def verb_at(i):
+ return len(args) > i and args[i].strip() in parity.HTTP_VERB_LITERALS
+
+ current, legacy = verb_at(2), verb_at(3)
+ if current and not legacy:
+ return parity.CURRENT_POSITIONAL_FIELDS
+ if legacy and not current:
+ return parity.POSITIONAL_FIELDS
+ return None
+
+
+def field_index(args: list, field_name: str):
+ """Positional index of a semantic field name, or None when the signature is
+ unrecognisable or the field is absent from it."""
+ fields = detect_positional_fields(args)
+ if fields is None:
+ return None
+ try:
+ return fields.index(field_name)
+ except ValueError:
+ return None
+
+
def find_resourcedoc_spans(source: str, marker: str = "resourceDocs += ResourceDoc("):
"""Yield (start_idx, end_idx_after_close_paren, endpoint_name, args_list)
for every non-commented occurrence of `marker` in `source`."""
@@ -414,10 +443,9 @@ def find_resourcedoc_spans(source: str, marker: str = "resourceDocs += ResourceD
except Exception:
args = []
name = None
- if len(args) >= 3:
- m = re.search(r"nameOf\(([a-zA-Z_][a-zA-Z0-9_]*)\)", args[2])
- if m:
- name = m.group(1)
+ name_idx = field_index(args, "partialFunctionName")
+ if name_idx is not None and len(args) > name_idx:
+ name = parity.endpoint_name(args[name_idx])
yield (j, k, name, args)
i = k
@@ -476,12 +504,12 @@ def reindent(expr: str) -> str:
return f"\n{body}\n{block_indent}"
-def cmd_lift(api_methods: Path, http4s: Path) -> int:
- api_src = api_methods.read_text()
+def cmd_lift(http4s: Path) -> int:
+ version = version_from_http4s_path(http4s)
h4_src = http4s.read_text()
- extracted = collect_liftweb_full(api_src)
- print(f"liftweb predecessors collected: {len(extracted)}")
+ extracted = collect_baseline_full(version)
+ print(f"Lift-era baseline entries collected for {version}: {len(extracted)}")
marker = detect_marker(h4_src)
spans = list(find_resourcedoc_spans(h4_src, marker=marker))
@@ -493,8 +521,25 @@ def cmd_lift(api_methods: Path, http4s: Path) -> int:
skipped_missing = 0
skipped_unchanged = 0
skipped_short_args = 0
+ unknown_signature = 0
for j, k, name, args in spans:
- if not name or name not in extracted or len(args) < 9:
+ # A registration whose signature we cannot classify is skipped, never
+ # guessed at: writing to guessed offsets would corrupt the file.
+ if len(args) >= 3 and detect_positional_fields(args) is None:
+ unknown_signature += 1
+ line_no = h4_src.count("\n", 0, j) + 1
+ print(
+ f" WARN: unrecognised ResourceDoc signature at "
+ f"{http4s.name}:{line_no} ({name or 'unnamed'}) — no verb literal at "
+ f"positional index 2 or 3; skipped",
+ file=sys.stderr,
+ )
+ continue
+ desc_idx = field_index(args, "description")
+ req_idx = field_index(args, "exampleRequestBody")
+ resp_idx = field_index(args, "successResponseBody")
+ max_idx = max((i for i in (desc_idx, req_idx, resp_idx) if i is not None), default=-1)
+ if not name or name not in extracted or max_idx < 0 or len(args) <= max_idx:
if not name or name not in extracted:
skipped_missing += 1
else:
@@ -502,16 +547,16 @@ def cmd_lift(api_methods: Path, http4s: Path) -> int:
continue
desc_l, req_l, resp_l = extracted[name]
if (
- args[6].strip() == desc_l
- and args[7].strip() == req_l
- and args[8].strip() == resp_l
+ args[desc_idx].strip() == desc_l
+ and args[req_idx].strip() == req_l
+ and args[resp_idx].strip() == resp_l
):
skipped_unchanged += 1
continue
new_args = args.copy()
- new_args[6] = desc_l
- new_args[7] = req_l
- new_args[8] = resp_l
+ new_args[desc_idx] = desc_l
+ new_args[req_idx] = req_l
+ new_args[resp_idx] = resp_l
line_start = new_src.rfind("\n", 0, j) + 1
prefix = new_src[line_start:j]
block_indent = re.match(r"\s*", prefix).group(0)
@@ -520,12 +565,24 @@ def cmd_lift(api_methods: Path, http4s: Path) -> int:
new_src = new_src[: paren_pos + 1] + block + new_src[k - 1 :]
patched += 1
- http4s.write_text(new_src)
- print(f"Patched: {patched}")
+ # Only write when every registration was understood: a non-zero exit that had
+ # already rewritten the file would leave a caller that treats failure as "nothing
+ # changed" with a modified file and no rollback.
+ if unknown_signature:
+ print(f"Refusing to write {http4s.name}: {unknown_signature} registration(s) "
+ f"could not be classified (see the WARNs above). No changes made.",
+ file=sys.stderr)
+ else:
+ http4s.write_text(new_src)
+ print(f"Patched: {patched}" + (" (NOT written)" if unknown_signature else ""))
print(f"Skipped (already up-to-date): {skipped_unchanged}")
print(f"Skipped (no liftweb match): {skipped_missing}")
print(f"Skipped (parse / arg-count): {skipped_short_args}")
- return 0
+ print(f"Skipped (unrecognised signature): {unknown_signature}")
+ # Non-zero on an unclassifiable registration: the tool's assumption about
+ # the constructor shape no longer holds everywhere, and silently patching
+ # the rest would hide that.
+ return 1 if unknown_signature else 0
# ─────────────────────────────────────────────────────────────────────────
@@ -733,8 +790,7 @@ def main(argv: list[str] | None = None) -> int:
)
sub = parser.add_subparsers(dest="cmd", required=True)
- lift_p = sub.add_parser("lift", help="Lift description/req/resp from commented liftweb predecessors.")
- lift_p.add_argument("--api-methods", required=True, type=Path)
+ lift_p = sub.add_parser("lift", help="Lift description/req/resp from the JSON baseline.")
lift_p.add_argument("--http4s", required=True, type=Path)
split_p = sub.add_parser(
@@ -752,7 +808,7 @@ def main(argv: list[str] | None = None) -> int:
args = parser.parse_args(argv)
if args.cmd == "lift":
- return cmd_lift(args.api_methods, args.http4s)
+ return cmd_lift(args.http4s)
if args.cmd == "split-init":
obj_name = args.object_name
if obj_name is None:
diff --git a/scripts/resource_doc_baseline/README.md b/scripts/resource_doc_baseline/README.md
new file mode 100644
index 0000000000..d20ede5a92
--- /dev/null
+++ b/scripts/resource_doc_baseline/README.md
@@ -0,0 +1,149 @@
+# ResourceDoc baseline
+
+This directory is the source of truth for the original Lift-era `ResourceDoc`
+documentation (summary, description, example bodies, error lists, tags) that
+used to be preserved as commented-out text inside the 12 `APIMethodsXYZ.scala`
+files. Those files have been deleted (see git history — `git log --follow --
+obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`, etc., from
+whichever commit removed them); this JSON is what
+`scripts/check_lift_http4s_resource_doc_parity.py` now reads instead, to keep
+auditing the live http4s implementation for accidental documentation drift
+from the original Lift design.
+
+## Files
+
+- `lift_resource_docs_vX_Y_Z.json` (one per API version, 12 total) — every
+ endpoint's Lift-era `ResourceDoc` fields, each stored as the **literal,
+ unevaluated Scala source snippet** it always was (e.g. an interpolated
+ triple-quoted description with `.stripMargin`, a `List(...)` tags
+ expression, an `X :: Y :: Nil` error list) — not a parsed or evaluated
+ value. This is not optional: `rehydrate_resource_docs.py` and
+ `restore_resource_doc_bodies.py` splice this text verbatim into a live
+ `.scala` file, so anything stored here must still be valid, reproducible
+ Scala source text.
+- `digest_manifest.json` — a signature proving the JSON above was exported
+ losslessly from the original `.scala` sources (see "Digest verification"
+ below). Only ever written by `export_and_verify.py --write`.
+- `parity_allowlist.json` — known, human-reviewed differences between the
+ Lift baseline and the current http4s implementation, so
+ `check_lift_http4s_resource_doc_parity.py` only fails on *new* drift, not
+ on this already-reviewed backlog. See "Maintaining the allowlist" below.
+- `export_and_verify.py` — the one-time (and re-runnable) export tool. Only
+ needed again if the JSON baseline itself is ever regenerated from a
+ different source (it shouldn't be, in the ordinary course of things — the
+ `.scala` files it reads from are gone).
+- `allowlist_helper.py` — prints one ready-to-paste allowlist entry with
+ correctly-computed digests. Use this instead of hand-computing sha256
+ hashes when adding to `parity_allowlist.json`.
+
+## Why JSON instead of keeping the `.scala` files around
+
+The 12 `APIMethodsXYZ.scala` files were themselves already dead code — every
+one had shrunk to a thin runtime shim (`object APIMethodsNNN { val
+ImplementationsX = Http4sNNN.ImplementationsX }`) plus thousands of lines of
+commented-out original Lift source kept only so the parity script could read
+it. Moving that text into JSON removes ~60,000 lines of dead Scala from the
+build (a `.scala` file the compiler does nothing with is still a `.scala`
+file every IDE/search/lint tool indexes) while keeping the actual
+information — the Lift design's documentation text — intact and just as
+readable as a diff of the parity report.
+
+## Digest verification (why you can trust the JSON matches what was deleted)
+
+Before the `.scala` files were deleted, `export_and_verify.py --write`:
+
+1. Extracted every `ResourceDoc` field from each live `.scala` file (the same
+ parser `check_lift_http4s_resource_doc_parity.py` already used) and
+ computed a sha256 digest of each `(version, endpoint, field)` value.
+2. Wrote the 12 JSON files.
+3. Re-read those JSON files back and computed the *same* digests from the
+ JSON content.
+4. Asserted the two digest sets were **identical — same keys, same values**,
+ not just the same count (a byte-for-byte round-trip proof, not a
+ plausibility check). Only on success did it write `digest_manifest.json`.
+
+If you ever need to re-verify the checked-in JSON hasn't drifted (e.g. after
+a hand-edit, or as a periodic sanity check), run:
+
+```sh
+python3 scripts/resource_doc_baseline/export_and_verify.py --check-only
+```
+
+This confirms the JSON still matches `digest_manifest.json`'s stored
+aggregate digest. (Its check against the original `.scala` sources is
+automatically skipped now that those files are gone — there's nothing left
+to compare against on that side.)
+
+## Maintaining the allowlist
+
+`parity_allowlist.json` has four sections:
+
+- **`rename_pairs`** — a Lift endpoint and an http4s endpoint that are the
+ same real endpoint (same HTTP verb + URL), just renamed during the http4s
+ migration. Each pair is bound to both sides' `(verb, url)` identity digest
+ — if either side's verb/url ever changes, the pair stops matching and the
+ two endpoints fall back to showing as ordinary only-lift/only-http4s
+ differences (which will then also need a decision).
+- **`only_in_lift`** / **`only_in_http4s`** — an endpoint that only exists on
+ one side, already reviewed as intentional (a Lift endpoint that was
+ retired, or a genuinely new http4s endpoint with no Lift predecessor).
+ Bound to that endpoint's `(verb, url)` identity digest.
+- **`field_mismatches`** — one field (`requestVerb`, `requestUrl`, `summary`,
+ `description`, `exampleRequestBody`, `successResponseBody`,
+ `errorResponseBodies`, or `tags`) on a shared endpoint whose Lift and
+ http4s text differ, already reviewed as an intentional improvement (a
+ fixed Lift bug, a clarified description, an updated example) rather than a
+ regression. Bound to both sides' normalized-value digest — reformatting
+ never counts as drift, but any real content change does.
+
+**Every entry is bound to a digest, not a name.** If the underlying value
+changes after being allowlisted, the digest no longer matches, the entry
+stops suppressing it, and the parity check goes red again on that specific
+item — the allowlist can't silently rot into "yes to everything forever."
+
+To add a new entry, don't hand-compute the digests — use the helper, which
+computes them from the current live data so they're guaranteed to match what
+the parity script itself will see:
+
+```sh
+python3 scripts/resource_doc_baseline/allowlist_helper.py rename-pair \
+ v3_1_0 someOldName someNewName "why this is the same endpoint, renamed"
+python3 scripts/resource_doc_baseline/allowlist_helper.py only-lift \
+ v2_1_0 someRetiredEndpoint "why this was intentionally retired"
+python3 scripts/resource_doc_baseline/allowlist_helper.py only-http4s \
+ v6_0_0 someNewEndpoint "why this has no Lift predecessor"
+python3 scripts/resource_doc_baseline/allowlist_helper.py field-mismatch \
+ v6_0_0 someEndpoint description "why the http4s text is fine as-is"
+```
+
+Paste the printed JSON object into the matching array in
+`parity_allowlist.json`, then re-run the parity check and confirm the entry
+is now consulted:
+
+```sh
+python3 scripts/check_lift_http4s_resource_doc_parity.py --report-stale-allowlist-entries
+```
+
+An allowlist entry that never matches anything (typo'd version/endpoint/
+field, or the difference it was covering no longer exists) shows up under
+"STALE ALLOWLIST ENTRIES" — that's a prompt to fix or remove it, not a
+failure by itself.
+
+**Never allowlist a real regression to make the check pass.** If a
+difference turns out to be a genuine bug (http4s dropped an error code Lift
+declared, a description now omits a real caveat, a URL changed meaning
+rather than just a template variable name), fix the http4s side instead, or
+leave the parity check red for that item and track the fix separately — the
+whole point of this tool is to catch exactly that class of drift.
+
+## Regenerating everything from scratch
+
+This should not normally be necessary — the 12 source `.scala` files are
+gone, so there is nothing left to re-export from. It would only apply if,
+hypothetically, a future change needed to rebuild the JSON from some other
+source of the original Lift text (e.g. checking out the pre-deletion commit).
+In that case: point `export_and_verify.py` at that source the same way it
+originally read the `.scala` files, run `--write`, confirm the digest gate
+passes, and then re-review `parity_allowlist.json` from scratch — a
+regenerated baseline's digests won't match the old allowlist's stored
+digests unless the extraction is byte-for-byte identical.
diff --git a/scripts/resource_doc_baseline/allowlist_helper.py b/scripts/resource_doc_baseline/allowlist_helper.py
new file mode 100644
index 0000000000..54948aa5bb
--- /dev/null
+++ b/scripts/resource_doc_baseline/allowlist_helper.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+"""
+allowlist_helper.py
+
+Prints a ready-to-paste JSON object for one new entry in
+scripts/resource_doc_baseline/parity_allowlist.json, with digests computed
+from the CURRENT live data (the JSON baseline + the current Http4s*.scala) —
+so the digests you paste in are guaranteed to match what
+check_lift_http4s_resource_doc_parity.py will compute the next time it runs.
+
+This tool only PRINTS; it never edits parity_allowlist.json itself. Paste the
+printed object into the right array, add your own "reason", and re-run
+check_lift_http4s_resource_doc_parity.py to confirm the entry is now consulted
+(look for "○ ... (allowlisted)" / "[allowlisted]" in its output, or pass
+--report-stale-allowlist-entries to catch a typo'd version/endpoint/field that
+never matches anything).
+
+Usage:
+ # A Lift endpoint and an http4s endpoint that are the same thing, renamed:
+ python3 scripts/resource_doc_baseline/allowlist_helper.py rename-pair \\
+ v3_1_0 addCardsForBank addCardForBank "Renamed during http4s migration"
+
+ # An endpoint that exists only on one side (already reviewed as intentional):
+ python3 scripts/resource_doc_baseline/allowlist_helper.py only-lift \\
+ v2_1_0 createTransactionRequestSepa "SEPA transaction-request type retired"
+ python3 scripts/resource_doc_baseline/allowlist_helper.py only-http4s \\
+ v6_0_0 createWebUiProps "New in http4s, no Lift predecessor"
+
+ # A field whose Lift vs http4s text differs, already reviewed as intentional:
+ python3 scripts/resource_doc_baseline/allowlist_helper.py field-mismatch \\
+ v6_0_0 getMetrics description "http4s description is more complete"
+"""
+
+import argparse
+import json
+import sys
+from pathlib import Path
+
+SCRIPT_DIR = Path(__file__).resolve().parent
+REPO_ROOT = SCRIPT_DIR.parents[1]
+sys.path.insert(0, str(REPO_ROOT / "scripts"))
+import check_lift_http4s_resource_doc_parity as parity # noqa: E402
+
+
+def get_docs(version: str):
+ lift_docs = parity.load_baseline_docs(version)
+ if lift_docs is None:
+ print(f"No JSON baseline for {version} — run export_and_verify.py --write first.", file=sys.stderr)
+ sys.exit(1)
+ http_path = parity.find_http4s_path(version)
+ if http_path is None:
+ print(f"No Http4s*.scala found for {version}.", file=sys.stderr)
+ sys.exit(1)
+ http_docs = parity.collect_resourcedocs(http_path)
+ return lift_docs, http_docs
+
+
+def cmd_rename_pair(args):
+ lift_docs, http_docs = get_docs(args.version)
+ if args.lift_name not in lift_docs:
+ print(f"'{args.lift_name}' not found in the Lift baseline for {args.version}.", file=sys.stderr)
+ sys.exit(1)
+ if args.http4s_name not in http_docs:
+ print(f"'{args.http4s_name}' not found in http4s for {args.version}.", file=sys.stderr)
+ sys.exit(1)
+ l = lift_docs[args.lift_name]
+ h = http_docs[args.http4s_name]
+ entry = {
+ "version": args.version,
+ "lift_name": args.lift_name,
+ "http4s_name": args.http4s_name,
+ "reason": args.reason,
+ "lift_identity_digest": parity.identity_digest(l.get("requestVerb", ""), l.get("requestUrl", "")),
+ "http4s_identity_digest": parity.identity_digest(h.get("requestVerb", ""), h.get("requestUrl", "")),
+ }
+ print(json.dumps(entry, indent=2))
+
+
+def cmd_only_one_side(args, docs_key: str):
+ lift_docs, http_docs = get_docs(args.version)
+ docs = lift_docs if docs_key == "lift" else http_docs
+ if args.endpoint not in docs:
+ print(f"'{args.endpoint}' not found on the {docs_key} side for {args.version}.", file=sys.stderr)
+ sys.exit(1)
+ d = docs[args.endpoint]
+ entry = {
+ "version": args.version,
+ "endpoint": args.endpoint,
+ "reason": args.reason,
+ "identity_digest": parity.identity_digest(d.get("requestVerb", ""), d.get("requestUrl", "")),
+ }
+ print(json.dumps(entry, indent=2))
+
+
+VALID_FIELDS = sorted(set(parity.POSITIONAL_FIELDS) | parity.NAMED_ARG_FIELDS)
+
+
+def cmd_field_mismatch(args):
+ # Without this an unknown field yields digests over the empty string for BOTH
+ # sides — a well-formed entry that silently matches nothing, leaving the
+ # reviewer to wonder why the audit is still red.
+ if args.field not in VALID_FIELDS:
+ print(f"Unknown field '{args.field}'. Valid fields: {', '.join(VALID_FIELDS)}",
+ file=sys.stderr)
+ sys.exit(2)
+ lift_docs, http_docs = get_docs(args.version)
+ if args.endpoint not in lift_docs or args.endpoint not in http_docs:
+ print(f"'{args.endpoint}' is not shared between Lift and http4s for {args.version} "
+ f"— use only-lift/only-http4s instead if it's missing on one side.", file=sys.stderr)
+ sys.exit(1)
+ lv = lift_docs[args.endpoint].get(args.field)
+ hv = http_docs[args.endpoint].get(args.field)
+ entry = {
+ "version": args.version,
+ "endpoint": args.endpoint,
+ "field": args.field,
+ "reason": args.reason,
+ "lift_digest": parity.field_digest(lv, args.field),
+ "http4s_digest": parity.field_digest(hv, args.field),
+ }
+ print(json.dumps(entry, indent=2))
+
+
+def main():
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
+ sub = ap.add_subparsers(dest="cmd", required=True)
+
+ p = sub.add_parser("rename-pair")
+ p.add_argument("version")
+ p.add_argument("lift_name")
+ p.add_argument("http4s_name")
+ p.add_argument("reason")
+
+ p = sub.add_parser("only-lift")
+ p.add_argument("version")
+ p.add_argument("endpoint")
+ p.add_argument("reason")
+
+ p = sub.add_parser("only-http4s")
+ p.add_argument("version")
+ p.add_argument("endpoint")
+ p.add_argument("reason")
+
+ p = sub.add_parser("field-mismatch")
+ p.add_argument("version")
+ p.add_argument("endpoint")
+ p.add_argument("field")
+ p.add_argument("reason")
+
+ args = ap.parse_args()
+ if args.cmd == "rename-pair":
+ cmd_rename_pair(args)
+ elif args.cmd == "only-lift":
+ cmd_only_one_side(args, "lift")
+ elif args.cmd == "only-http4s":
+ cmd_only_one_side(args, "http4s")
+ elif args.cmd == "field-mismatch":
+ cmd_field_mismatch(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/resource_doc_baseline/digest_manifest.json b/scripts/resource_doc_baseline/digest_manifest.json
new file mode 100644
index 0000000000..4699d6626e
--- /dev/null
+++ b/scripts/resource_doc_baseline/digest_manifest.json
@@ -0,0 +1,21 @@
+{
+ "schema_version": 1,
+ "generated_at": "2026-09-01T13:49:22.393516+00:00",
+ "aggregate_digest": "sha256:e10a84fbea3d9bf592ea6489a986e03dbff20772fa4fe85e26e754dc2a7c6461",
+ "per_field_count": 9288,
+ "per_version_endpoint_counts": {
+ "v1_2_1": 70,
+ "v1_3_0": 3,
+ "v1_4_0": 10,
+ "v2_0_0": 37,
+ "v2_1_0": 28,
+ "v2_2_0": 18,
+ "v3_0_0": 47,
+ "v3_1_0": 102,
+ "v4_0_0": 256,
+ "v5_0_0": 39,
+ "v5_1_0": 111,
+ "v6_0_0": 243
+ },
+ "source_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980"
+}
diff --git a/scripts/resource_doc_baseline/export_and_verify.py b/scripts/resource_doc_baseline/export_and_verify.py
new file mode 100644
index 0000000000..2a47b0ac6b
--- /dev/null
+++ b/scripts/resource_doc_baseline/export_and_verify.py
@@ -0,0 +1,396 @@
+#!/usr/bin/env python3
+"""
+export_and_verify.py
+
+One-time (and re-runnable) tool that exports the Lift-era ResourceDoc metadata
+currently living as commented-out text inside the 12 APIMethods*.scala files
+into a JSON baseline under scripts/resource_doc_baseline/, and proves the
+export is lossless before anything downstream — most importantly, deletion of
+those .scala files — is allowed to trust it.
+
+Every field is stored as the literal, unevaluated Scala source snippet
+check_lift_http4s_resource_doc_parity.py already extracts (e.g. an
+interpolated triple-quoted description with .stripMargin, a List(...) tags
+expression, an X :: Y :: Nil error list) — not a parsed or evaluated value.
+rehydrate_resource_docs.py and restore_resource_doc_bodies.py splice this
+text verbatim into a live .scala file; a JSON baseline that stored evaluated
+values would break that.
+
+Modes:
+ --write Export .scala -> JSON, verify the round-trip digest set
+ matches EXACTLY (same keys, same values — not just the same
+ count), and only then write digest_manifest.json. On any
+ mismatch, nothing is written past the JSON files themselves
+ and the exit code is 1 — treat that as "do not proceed to
+ deleting the .scala files".
+ --check-only Re-verify an already-exported baseline: the checked-in JSON
+ must still match digest_manifest.json (catches hand-edits),
+ and — while the APIMethods*.scala files still exist — the
+ .scala sources must still match too (catches the JSON going
+ stale before the deletion commit lands). Once those files are
+ deleted, the .scala-side half of this check is skipped.
+
+Read-only towards the .scala sources in both modes; only ever writes into
+scripts/resource_doc_baseline/.
+
+Usage:
+ python3 scripts/resource_doc_baseline/export_and_verify.py --write
+ python3 scripts/resource_doc_baseline/export_and_verify.py --check-only
+"""
+
+import argparse
+import hashlib
+import json
+import re
+import subprocess
+import sys
+from collections import OrderedDict
+from datetime import datetime, timezone
+from pathlib import Path
+
+SCRIPT_DIR = Path(__file__).resolve().parent
+REPO_ROOT = SCRIPT_DIR.parents[1]
+BASELINE_DIR = SCRIPT_DIR
+
+sys.path.insert(0, str(REPO_ROOT / "scripts"))
+import check_lift_http4s_resource_doc_parity as parity # noqa: E402
+
+# Full set of positional fields persisted per endpoint — broader than parity's
+# own DEFAULT_DIFF_FIELDS, since this check is about lossless *export*, not
+# comparison against http4s.
+PERSISTED_FIELDS = [
+ "partialFunctionName",
+ "requestVerb",
+ "requestUrl",
+ "summary",
+ "description",
+ "exampleRequestBody",
+ "successResponseBody",
+ "errorResponseBodies",
+ "tags",
+]
+
+FIELD_JSON_KEYS = {
+ "partialFunctionName": "partial_function_name_raw",
+ "requestVerb": "request_verb",
+ "requestUrl": "request_url",
+ "summary": "summary",
+ "description": "description",
+ "exampleRequestBody": "example_request_body",
+ "successResponseBody": "success_response_body",
+ "errorResponseBodies": "error_response_bodies",
+ "tags": "tags",
+}
+JSON_KEY_TO_FIELD = {v: k for k, v in FIELD_JSON_KEYS.items()}
+
+
+def sha256_hex(s: str) -> str:
+ return hashlib.sha256(s.encode("utf-8")).hexdigest()
+
+
+def current_git_commit() -> str:
+ try:
+ result = subprocess.run(
+ ["git", "rev-parse", "HEAD"],
+ cwd=REPO_ROOT, capture_output=True, text=True, check=True,
+ )
+ return result.stdout.strip()
+ except Exception:
+ return "unknown"
+
+
+def discover_versions():
+ return sorted(
+ d.name for d in parity.API_ROOT.iterdir()
+ if d.is_dir() and parity.VERSION_RE.match(d.name)
+ )
+
+
+def find_lift_path(version: str):
+ """Return the canonical APIMethodsNNN.scala path for a version, or None.
+
+ Reuses parity.find_pair_for_version (which also requires a Http4s* file to
+ exist in the same directory) and rejects decorator files like
+ APIMethodsCustom300.scala the same way parity.py's own `pick()` does.
+ """
+ vdir = parity.API_ROOT / version
+ if not vdir.is_dir():
+ return None
+ pair = parity.find_pair_for_version(vdir)
+ if not pair:
+ return None
+ lift_path, _http_path = pair
+ if not re.match(r"^APIMethods\d+\.scala$", lift_path.name):
+ return None
+ return lift_path
+
+
+def digest_tuples(version: str, docs: "OrderedDict[str, OrderedDict]"):
+ """Yield (version, endpoint, field, digest) for every persisted field.
+
+ Uses the RAW (unnormalized) string content's sha256 — this proves
+ byte-exact round-tripping through JSON, not semantic equivalence (that
+ tolerance belongs to the parity script's allowlist, not here).
+ """
+ tuples = []
+ for name, args in docs.items():
+ for field in PERSISTED_FIELDS:
+ if field in args:
+ tuples.append((version, name, field, sha256_hex(args[field])))
+ for named_field in sorted(parity.NAMED_ARG_FIELDS):
+ if named_field in args:
+ tuples.append((version, name, f"extra:{named_field}", sha256_hex(args[named_field])))
+ return tuples
+
+
+def to_digest_map(tuples):
+ d = {}
+ for version, endpoint, field, digest in tuples:
+ d[(version, endpoint, field)] = digest
+ return d
+
+
+def build_version_baseline_json(version: str, source_file: Path, docs, git_commit: str):
+ endpoints = OrderedDict()
+ for name, args in docs.items():
+ entry = OrderedDict()
+ for field in PERSISTED_FIELDS:
+ if field in args:
+ entry[FIELD_JSON_KEYS[field]] = args[field]
+ extra = OrderedDict()
+ for named_field in sorted(parity.NAMED_ARG_FIELDS):
+ if named_field in args:
+ extra[named_field] = args[named_field]
+ if extra:
+ entry["extra_named_args"] = extra
+ endpoints[name] = entry
+ return OrderedDict([
+ ("schema_version", 1),
+ ("version", version),
+ ("source_file", str(source_file.relative_to(REPO_ROOT))),
+ ("exported_from_git_commit", git_commit),
+ ("endpoint_count", len(endpoints)),
+ ("endpoints", endpoints),
+ ])
+
+
+def docs_from_baseline_json(baseline: dict):
+ """Inverse of build_version_baseline_json: JSON -> OrderedDict[name -> args],
+ using the ORIGINAL Scala field names (partialFunctionName, requestVerb, ...)
+ so digest_tuples() can be applied uniformly to both the .scala-derived and
+ JSON-derived docs.
+ """
+ docs = OrderedDict()
+ for name, entry in baseline["endpoints"].items():
+ args = OrderedDict()
+ for json_key, value in entry.items():
+ if json_key == "extra_named_args":
+ for k, v in value.items():
+ args[k] = v
+ continue
+ field = JSON_KEY_TO_FIELD.get(json_key)
+ if field:
+ args[field] = value
+ docs[name] = args
+ return docs
+
+
+def aggregate_digest(digest_map: dict) -> str:
+ serializable = sorted(
+ [list(k) + [v] for k, v in digest_map.items()]
+ )
+ return hashlib.sha256(
+ json.dumps(serializable, sort_keys=True, separators=(",", ":")).encode("utf-8")
+ ).hexdigest()
+
+
+def report_mismatch(map_a, map_b, label_a: str, label_b: str):
+ keys_a, keys_b = set(map_a), set(map_b)
+ missing_in_b = sorted(keys_a - keys_b)
+ extra_in_b = sorted(keys_b - keys_a)
+ changed = sorted(k for k in (keys_a & keys_b) if map_a[k] != map_b[k])
+ if not (missing_in_b or extra_in_b or changed):
+ return True
+ print(f"DIGEST MISMATCH between {label_a} and {label_b}:", file=sys.stderr)
+ for k in missing_in_b[:50]:
+ print(f" in {label_a} but missing from {label_b}: {k}", file=sys.stderr)
+ for k in extra_in_b[:50]:
+ print(f" in {label_b} but missing from {label_a}: {k}", file=sys.stderr)
+ for k in changed[:50]:
+ print(f" value differs: {k}", file=sys.stderr)
+ total = len(missing_in_b) + len(extra_in_b) + len(changed)
+ if total > 150:
+ print(f" ... and {total - 150} more", file=sys.stderr)
+ return False
+
+
+def cmd_write() -> int:
+ versions = discover_versions()
+ git_commit = current_git_commit()
+ scala_digests = []
+ json_digests = []
+ per_version_endpoint_counts = OrderedDict()
+ BASELINE_DIR.mkdir(parents=True, exist_ok=True)
+
+ exported_versions = []
+ coverage_gaps = []
+ for v in versions:
+ lift_path = find_lift_path(v)
+ if lift_path is None:
+ continue
+ docs, stats = parity.collect_resourcedocs_with_stats(lift_path)
+ if not docs:
+ continue
+ # Coverage, not just fidelity: the digest comparison below only proves the
+ # JSON stores what the parser produced. It cannot see a registration the
+ # parser never produced, which is exactly the loss that would matter once
+ # these .scala files are deleted. So account for every block found.
+ if stats["unparsed"] or stats["duplicates"]:
+ coverage_gaps.append((v, lift_path, stats))
+ scala_digests.extend(digest_tuples(v, docs))
+ baseline = build_version_baseline_json(v, lift_path, docs, git_commit)
+ out_path = BASELINE_DIR / f"lift_resource_docs_{v}.json"
+ out_path.write_text(
+ json.dumps(baseline, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
+ )
+ per_version_endpoint_counts[v] = len(docs)
+ exported_versions.append(v)
+
+ reloaded = json.loads(out_path.read_text(encoding="utf-8"))
+ reloaded_docs = docs_from_baseline_json(reloaded)
+ json_digests.extend(digest_tuples(v, reloaded_docs))
+
+ if coverage_gaps:
+ print(
+ "\nEXPORT IS NOT COMPLETE — some ResourceDoc registrations were found in the "
+ "source but not stored, so the digest check below cannot vouch for them:",
+ file=sys.stderr,
+ )
+ for v, path, st in coverage_gaps:
+ print(
+ f" {v} ({path.relative_to(REPO_ROOT)}): {st['blocks']} registrations found, "
+ f"{st['unparsed']} unparsed, {st['duplicates']} dropped as duplicate names"
+ + (f" ({', '.join(st['duplicate_names'])})" if st["duplicate_names"] else ""),
+ file=sys.stderr,
+ )
+ print(
+ "digest_manifest.json was NOT written. Do not delete the .scala sources.",
+ file=sys.stderr,
+ )
+ return 1
+
+ map_scala = to_digest_map(scala_digests)
+ map_json = to_digest_map(json_digests)
+ if not report_mismatch(map_scala, map_json, ".scala extraction", "JSON round-trip"):
+ print(
+ "\nExport is NOT lossless — digest_manifest.json was NOT written. "
+ "Do not proceed to deleting the .scala files.",
+ file=sys.stderr,
+ )
+ return 1
+
+ agg = aggregate_digest(map_scala)
+ manifest = OrderedDict([
+ ("schema_version", 1),
+ ("generated_at", datetime.now(timezone.utc).isoformat()),
+ ("aggregate_digest", f"sha256:{agg}"),
+ ("per_field_count", len(map_scala)),
+ ("per_version_endpoint_counts", per_version_endpoint_counts),
+ ("source_git_commit", git_commit),
+ ])
+ (BASELINE_DIR / "digest_manifest.json").write_text(
+ json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
+ )
+ total_endpoints = sum(per_version_endpoint_counts.values())
+ print(
+ f"OK: {len(map_scala)} field digests match exactly across "
+ f"{len(exported_versions)} versions ({total_endpoints} endpoints)."
+ )
+ print(f"Wrote {len(exported_versions)} baseline files + digest_manifest.json to {BASELINE_DIR}")
+ return 0
+
+
+def cmd_check_only() -> int:
+ manifest_path = BASELINE_DIR / "digest_manifest.json"
+ if not manifest_path.exists():
+ print("No digest_manifest.json found — run --write first.", file=sys.stderr)
+ return 1
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
+
+ versions = discover_versions()
+ json_digests = []
+ scala_digests = []
+ any_scala_present = False
+ any_scala_missing = False
+
+ for v in versions:
+ baseline_path = BASELINE_DIR / f"lift_resource_docs_{v}.json"
+ if not baseline_path.exists():
+ continue
+ baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
+ docs_json = docs_from_baseline_json(baseline)
+ json_digests.extend(digest_tuples(v, docs_json))
+
+ lift_path = find_lift_path(v)
+ if lift_path is not None:
+ any_scala_present = True
+ docs_scala = parity.collect_resourcedocs(lift_path)
+ scala_digests.extend(digest_tuples(v, docs_scala))
+ else:
+ any_scala_missing = True
+
+ map_json = to_digest_map(json_digests)
+ agg_json = aggregate_digest(map_json)
+ ok = True
+ if f"sha256:{agg_json}" != manifest["aggregate_digest"]:
+ print(
+ "Checked-in JSON baseline no longer matches digest_manifest.json "
+ "(was it hand-edited without re-running --write?).",
+ file=sys.stderr,
+ )
+ ok = False
+ else:
+ print("OK: checked-in JSON baseline matches digest_manifest.json.")
+
+ if any_scala_present:
+ map_scala = to_digest_map(scala_digests)
+ if not report_mismatch(map_scala, map_json, ".scala sources (current)", "checked-in JSON baseline"):
+ print(
+ "\n.scala sources have drifted from the checked-in JSON baseline "
+ "since it was exported — re-run --write.",
+ file=sys.stderr,
+ )
+ ok = False
+ else:
+ print("OK: current .scala sources still match the checked-in JSON baseline.")
+ if any_scala_missing and not any_scala_present:
+ print(
+ "APIMethods*.scala files are gone (already deleted) — skipped the "
+ ".scala-side comparison; only JSON-vs-manifest was checked."
+ )
+ elif any_scala_missing:
+ print(
+ "Some but not all APIMethods*.scala files are present — unexpected "
+ "partial deletion state; treat this as a red flag even though the "
+ "digests above may have matched for the files that do still exist.",
+ file=sys.stderr,
+ )
+ ok = False
+
+ return 0 if ok else 1
+
+
+def main() -> int:
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
+ mode = ap.add_mutually_exclusive_group(required=True)
+ mode.add_argument("--write", action="store_true", help="Export .scala -> JSON and verify losslessness")
+ mode.add_argument("--check-only", action="store_true", help="Re-verify an existing export")
+ args = ap.parse_args()
+
+ if args.write:
+ return cmd_write()
+ return cmd_check_only()
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v1_2_1.json b/scripts/resource_doc_baseline/lift_resource_docs_v1_2_1.json
new file mode 100644
index 0000000000..fb6c8bc7e2
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v1_2_1.json
@@ -0,0 +1,779 @@
+{
+ "schema_version": 1,
+ "version": "v1_2_1",
+ "source_file": "obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 70,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getBanks": {
+ "partial_function_name_raw": "\"getBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Get Banks\"",
+ "description": "\"\"\"Get banks on this API instance\n |Returns a list of banks supported on this server:\n |\n |* ID used as parameter in URLs\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "banksJSON",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagBank :: apiTagPsd2 :: apiTagOldStyle :: Nil"
+ },
+ "bankById": {
+ "partial_function_name_raw": "\"bankById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID\"",
+ "summary": "\"Get Bank\"",
+ "description": "\"\"\"Get the bank specified by BANK_ID\n |Returns information about a single bank specified by BANK_ID including:\n |\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankNotFound)",
+ "tags": "apiTagBank :: apiTagPsd2 :: apiTagOldStyle :: Nil"
+ },
+ "getPrivateAccountsAllBanks": {
+ "partial_function_name_raw": "\"getPrivateAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/accounts\"",
+ "summary": "\"Get accounts at all banks (Private, inc views)\"",
+ "description": "s\"\"\"Returns the list of accounts at that the user has access to at all banks.\n |For each account the API returns the account ID and the available views.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagAccount :: apiTagPsd2 :: apiTagOldStyle :: Nil"
+ },
+ "privateAccountsAllBanks": {
+ "partial_function_name_raw": "\"privateAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/accounts/private\"",
+ "summary": "\"Get private accounts at all banks (Authenticated access)\"",
+ "description": "\"\"\"Returns the list of private accounts the user has access to at all banks.\n |For each account the API returns the ID and the available views.\n |\n |Authentication via OAuth is required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagAccount :: apiTagPsd2 :: apiTagOldStyle :: Nil"
+ },
+ "publicAccountsAllBanks": {
+ "partial_function_name_raw": "\"publicAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/accounts/public\"",
+ "summary": "\"Get public accounts at all banks (Anonymous access)\"",
+ "description": "\"\"\"\n |Returns the list of private accounts the user has access to at all banks.\n |For each account the API returns the ID and the available views. \n |Authentication via OAuth is required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagAccount :: apiTagOldStyle :: Nil"
+ },
+ "getPrivateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"getPrivateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts\"",
+ "summary": "\"Get accounts at bank (Private)\"",
+ "description": "s\"\"\"Returns the list of accounts at BANK_ID that the user has access to.\n |For each account the API returns the account ID and the available views.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankNotFound)",
+ "tags": "apiTagAccount :: apiTagOldStyle :: Nil"
+ },
+ "privateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"privateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/private\"",
+ "summary": "\"Get private accounts at one bank\"",
+ "description": "s\"\"\"Returns the list of private accounts at BANK_ID that the user has access to.\n |For each account the API returns the ID and the available views.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankNotFound)",
+ "tags": "List(apiTagAccount, apiTagPsd2, apiTagOldStyle)"
+ },
+ "publicAccountsAtOneBank": {
+ "partial_function_name_raw": "\"publicAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/public\"",
+ "summary": "\"Get public accounts at one bank (Anonymous access)\"",
+ "description": "\"\"\"Returns a list of the public accounts at BANK_ID. For each account the API returns the ID and the available views.\n |\n |Authentication via OAuth is not required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankNotFound)",
+ "tags": "apiTagAccountPublic :: apiTagAccount :: apiTagPublicData :: apiTagOldStyle :: Nil"
+ },
+ "accountById": {
+ "partial_function_name_raw": "\"accountById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get account by id\"",
+ "description": "s\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |* Available views\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |${userAuthenticationMessage(false)}\n |\n |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedAccountJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankAccountNotFound)",
+ "tags": "apiTagAccount :: apiTagOldStyle :: Nil"
+ },
+ "updateAccountLabel": {
+ "partial_function_name_raw": "\"updateAccountLabel\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Update Account Label\"",
+ "description": "s\"\"\"Update the label for the account. The label is how the account is known to the account owner e.g. 'My savings account'\n |\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "updateAccountJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(InvalidJsonFormat, AuthenticatedUserIsRequired, UnknownError, BankAccountNotFound, \"user does not have access to owner view on account\")",
+ "tags": "List(apiTagAccount)"
+ },
+ "getViewsForBankAccount": {
+ "partial_function_name_raw": "\"getViewsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Get Views for Account\"",
+ "description": "s\"\"\"#Views\n |\n |\n |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.\n |\n |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.\n |\n |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.\n |\n |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.\n |\n |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.\n |\n |**Metadata:**\n |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.\n |\n |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).\n |\n |# All\n |*Optional*\n |\n |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJSONV121",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankAccountNotFound, UnknownError, \"user does not have owner access\")",
+ "tags": "List(apiTagView, apiTagAccount, apiTagOldStyle)"
+ },
+ "createViewForBankAccount": {
+ "partial_function_name_raw": "\"createViewForBankAccount\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Create View\"",
+ "description": "s\"\"\"#Create a view on bank account\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n | The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\"\"\"",
+ "example_request_body": "createViewJsonV121",
+ "success_response_body": "viewJSONV121",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n BankAccountNotFound,\n UnknownError,\n \"user does not have owner access\"\n )",
+ "tags": "List(apiTagAccount, apiTagView, apiTagOldStyle)"
+ },
+ "updateViewForBankAccount": {
+ "partial_function_name_raw": "\"updateViewForBankAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Update View\"",
+ "description": "s\"\"\"Update an existing view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateViewJsonV121",
+ "success_response_body": "viewJSONV121",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n UnknownError,\n \"user does not have owner access\"\n )",
+ "tags": "List(apiTagAccount, apiTagView, apiTagOldStyle)"
+ },
+ "deleteViewForBankAccount": {
+ "partial_function_name_raw": "\"deleteViewForBankAccount\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Delete Custom View\"",
+ "description": "\"Deletes the custom view specified by VIEW_ID on the bank account specified by ACCOUNT_ID at bank BANK_ID\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"user does not have owner access\"\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "getPermissionsForBankAccount": {
+ "partial_function_name_raw": "\"getPermissionsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions\"",
+ "summary": "\"Get access\"",
+ "description": "s\"\"\"Returns the list of the permissions at BANK_ID for account ACCOUNT_ID, with each time a pair composed of the user and the views that he has access to.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "permissionsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagView, apiTagAccount, apiTagEntitlement, apiTagOldStyle)"
+ },
+ "getPermissionForUserForBankAccount": {
+ "partial_function_name_raw": "\"getPermissionForUserForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER_ID/USER_ID\"",
+ "summary": "\"Get access for specific user\"",
+ "description": "s\"\"\"Returns the list of the views at BANK_ID for account ACCOUNT_ID that a USER_ID at their provider PROVIDER_ID has access to.\n |All url parameters must be [%-encoded](http://en.wikipedia.org/wiki/Percent-encoding), which is often especially relevant for USER_ID and PROVIDER_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJSONV121",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"user does not have access to owner view on account\"\n )",
+ "tags": "List(apiTagAccount, apiTagView, apiTagEntitlement, apiTagOldStyle)"
+ },
+ "addPermissionForUserForBankAccountForMultipleViews": {
+ "partial_function_name_raw": "\"addPermissionForUserForBankAccountForMultipleViews\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID/views\"",
+ "summary": "\"Grant User access to a list of views\"",
+ "description": "s\"\"\"Grants the user identified by PROVIDER_ID at their provider PROVIDER access to a list of views at BANK_ID for account ACCOUNT_ID.\n |\n |All url parameters must be [%-encoded](http://en.wikipedia.org/wiki/Percent-encoding), which is often especially relevant for PROVIDER_ID and PROVIDER.\n |\n |${userAuthenticationMessage(true)}\n |\n |The User needs to have access to the owner view.\"\"\"",
+ "example_request_body": "viewIdsJson",
+ "success_response_body": "viewsJSONV121",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"wrong format JSON\",\n \"could not save the privilege\",\n \"user does not have access to owner view on account\"\n )",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)"
+ },
+ "addPermissionForUserForBankAccountForOneView": {
+ "partial_function_name_raw": "\"addPermissionForUserForBankAccountForOneView\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID/views/VIEW_ID\"",
+ "summary": "\"Grant User access to View\"",
+ "description": "s\"\"\"Grants the User identified by PROVIDER_ID at PROVIDER access to the view VIEW_ID at BANK_ID for account ACCOUNT_ID.\n |\n |All url parameters must be [%-encoded](http://en.wikipedia.org/wiki/Percent-encoding), which is often especially relevant for PROVIDER and PROVIDER_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |Granting access to a public view will return an error message, as the user already has access.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewJSONV121",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n UserLacksPermissionCanGrantAccessToViewForTargetAccount,\n \"could not save the privilege\",\n \"user does not have access to owner view on account\"\n )",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)"
+ },
+ "removePermissionForUserForBankAccountForOneView": {
+ "partial_function_name_raw": "\"removePermissionForUserForBankAccountForOneView\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID/views/VIEW_ID\"",
+ "summary": "\"Revoke access to one View\"",
+ "description": "s\"\"\"Revokes access to a View on an Account for a certain User.\n |\n |$generalRevokeAccessToViewText\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"could not save the privilege\",\n \"user does not have access to owner view on account\",\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagEntitlement, apiTagOwnerRequired)"
+ },
+ "removePermissionForUserForBankAccountForAllViews": {
+ "partial_function_name_raw": "\"removePermissionForUserForBankAccountForAllViews\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID/views\"",
+ "summary": "\"Revoke access to all Views on Account\"",
+ "description": "s\"\"\"\"Revokes access to all Views on an Account for a certain User.\n |\n |$generalRevokeAccessToViewText\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"user does not have access to owner view on account\"\n )",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)"
+ },
+ "getOtherAccountsForBankAccount": {
+ "partial_function_name_raw": "\"getOtherAccountsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts\"",
+ "summary": "\"Get Other Accounts of one Account\"",
+ "description": "s\"\"\"Returns data about all the other accounts that have shared at least one transaction with the ACCOUNT_ID at BANK_ID.\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view VIEW_ID is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountsJSON",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount, apiTagPsd2, apiTagOldStyle)"
+ },
+ "getOtherAccountByIdForBankAccount": {
+ "partial_function_name_raw": "\"getOtherAccountByIdForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID\"",
+ "summary": "\"Get Other Account by Id\"",
+ "description": "s\"\"\"Returns data about the Other Account that has shared at least one transaction with ACCOUNT_ID at BANK_ID.\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountJSON",
+ "error_response_bodies": "List(BankAccountNotFound, UnknownError)",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ },
+ "getOtherAccountMetadata": {
+ "partial_function_name_raw": "\"getOtherAccountMetadata\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata\"",
+ "summary": "\"Get Other Account Metadata\"",
+ "description": "\"\"\"Get metadata of one other account.\n |Returns only the metadata about one other bank account (OTHER_ACCOUNT_ID) that had shared at least one transaction with ACCOUNT_ID at BANK_ID.\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountMetadataJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, \"the view does not allow metadata access\")",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "getCounterpartyPublicAlias": {
+ "partial_function_name_raw": "\"getCounterpartyPublicAlias\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/public_alias\"",
+ "summary": "\"Get public alias of other bank account\"",
+ "description": "s\"\"\"Returns the public alias of the other account OTHER_ACCOUNT_ID.\n |${userAuthenticationMessage(false)}\n |${userAuthenticationMessage(true)} if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "aliasJSON",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n UnknownError,\n \"the view does not allow metadata access\",\n \"the view does not allow public alias access\"\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyPublicAlias": {
+ "partial_function_name_raw": "\"addCounterpartyPublicAlias\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/public_alias\"",
+ "summary": "\"Add public alias to other bank account\"",
+ "description": "s\"\"\"Creates the public alias for the other account OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\n |\n |Note: Public aliases are automatically generated for new 'other accounts / counterparties', so this call should only be used if\n |the public alias was deleted.\n |\n |The VIEW_ID parameter should be a view the caller is permitted to access to and that has permission to create public aliases.\"\"\"",
+ "example_request_body": "aliasJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError,\n \"the view does not allow metadata access\",\n \"the view does not allow adding a public alias\",\n \"Alias cannot be added\",\n \"public alias added\"\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyPublicAlias": {
+ "partial_function_name_raw": "\"updateCounterpartyPublicAlias\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/public_alias\"",
+ "summary": "\"Update public alias of other bank account\"",
+ "description": "s\"\"\"Updates the public alias of the other account / counterparty OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "aliasJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n \"the view does not allow metadata access\",\n \"the view does not allow updating the public alias\",\n \"Alias cannot be updated\",\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyPublicAlias": {
+ "partial_function_name_raw": "\"deleteCounterpartyPublicAlias\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/public_alias\"",
+ "summary": "\"Delete Counterparty Public Alias\"",
+ "description": "s\"\"\"Deletes the public alias of the other account OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow deleting the public alias\",\n \"Alias cannot be deleted\",\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "getOtherAccountPrivateAlias": {
+ "partial_function_name_raw": "\"getOtherAccountPrivateAlias\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/private_alias\"",
+ "summary": "\"Get Other Account Private Alias\"",
+ "description": "s\"\"\"Returns the private alias of the other account OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "aliasJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow private alias access\",\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addOtherAccountPrivateAlias": {
+ "partial_function_name_raw": "\"addOtherAccountPrivateAlias\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/private_alias\"",
+ "summary": "\"Create Other Account Private Alias\"",
+ "description": "s\"\"\"Creates a private alias for the other account OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "aliasJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow adding a private alias\",\n \"Alias cannot be added\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyPrivateAlias": {
+ "partial_function_name_raw": "\"updateCounterpartyPrivateAlias\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/private_alias\"",
+ "summary": "\"Update Counterparty Private Alias\"",
+ "description": "s\"\"\"Updates the private alias of the counterparty (AKA other account) OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "aliasJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating the private alias\",\n \"Alias cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyPrivateAlias": {
+ "partial_function_name_raw": "\"deleteCounterpartyPrivateAlias\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/private_alias\"",
+ "summary": "\"Delete Counterparty Private Alias\"",
+ "description": "s\"\"\"Deletes the private alias of the other account OTHER_ACCOUNT_ID.\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow deleting the private alias\",\n \"Alias cannot be deleted\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyMoreInfo": {
+ "partial_function_name_raw": "\"addCounterpartyMoreInfo\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/more_info\"",
+ "summary": "\"Add Counterparty More Info\"",
+ "description": "\"Add a description of the counter party from the perpestive of the account e.g. My dentist\"",
+ "example_request_body": "moreInfoJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n NoViewPermission,\n \"the view \" + viewIdSwagger + \"does not allow adding more info\",\n \"More Info cannot be added\",\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyMoreInfo": {
+ "partial_function_name_raw": "\"updateCounterpartyMoreInfo\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/more_info\"",
+ "summary": "\"Update Counterparty More Info\"",
+ "description": "\"Update the more info description of the counter party from the perpestive of the account e.g. My dentist\"",
+ "example_request_body": "moreInfoJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating more info\",\n \"More Info cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyMoreInfo": {
+ "partial_function_name_raw": "\"deleteCounterpartyMoreInfo\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/more_info\"",
+ "summary": "\"Delete more info of other bank account\"",
+ "description": "\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow deleting more info\",\n \"More Info cannot be deleted\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyUrl": {
+ "partial_function_name_raw": "\"addCounterpartyUrl\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/url\"",
+ "summary": "\"Add url to other bank account\"",
+ "description": "\"A url which represents the counterparty (home page url etc.)\"",
+ "example_request_body": "urlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow adding a url\",\n \"URL cannot be added\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyUrl": {
+ "partial_function_name_raw": "\"updateCounterpartyUrl\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/url\"",
+ "summary": "\"Update url of other bank account\"",
+ "description": "\"A url which represents the counterparty (home page url etc.)\"",
+ "example_request_body": "urlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n NoViewPermission,\n ViewNotFound,\n \"URL cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyUrl": {
+ "partial_function_name_raw": "\"deleteCounterpartyUrl\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/url\"",
+ "summary": "\"Delete url of other bank account\"",
+ "description": "\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow deleting a url\",\n \"URL cannot be deleted\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyImageUrl": {
+ "partial_function_name_raw": "\"addCounterpartyImageUrl\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/image_url\"",
+ "summary": "\"Add image url to other bank account\"",
+ "description": "\"Add a url that points to the logo of the counterparty\"",
+ "example_request_body": "imageUrlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow adding an image url\",\n \"URL cannot be added\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyImageUrl": {
+ "partial_function_name_raw": "\"updateCounterpartyImageUrl\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/image_url\"",
+ "summary": "\"Update Counterparty Image Url\"",
+ "description": "\"Update the url that points to the logo of the counterparty\"",
+ "example_request_body": "imageUrlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating an image url\",\n \"URL cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyImageUrl": {
+ "partial_function_name_raw": "\"deleteCounterpartyImageUrl\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/image_url\"",
+ "summary": "\"Delete Counterparty Image URL\"",
+ "description": "\"Delete image url of other bank account\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyOpenCorporatesUrl": {
+ "partial_function_name_raw": "\"addCounterpartyOpenCorporatesUrl\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/open_corporates_url\"",
+ "summary": "\"Add Open Corporates URL to Counterparty\"",
+ "description": "\"Add open corporates url to other bank account\"",
+ "example_request_body": "openCorporateUrlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow adding an open corporate url\",\n \"URL cannot be added\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyOpenCorporatesUrl": {
+ "partial_function_name_raw": "\"updateCounterpartyOpenCorporatesUrl\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/open_corporates_url\"",
+ "summary": "\"Update Open Corporates Url of Counterparty\"",
+ "description": "\"Update open corporate url of other bank account\"",
+ "example_request_body": "openCorporateUrlJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating an open corporate url\",\n \"URL cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyOpenCorporatesUrl": {
+ "partial_function_name_raw": "\"deleteCounterpartyOpenCorporatesUrl\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/open_corporates_url\"",
+ "summary": "\"Delete Counterparty Open Corporates URL\"",
+ "description": "\"Delete open corporate url of other bank account\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow deleting an open corporate url\",\n \"URL cannot be deleted\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyCorporateLocation": {
+ "partial_function_name_raw": "\"addCounterpartyCorporateLocation\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/corporate_location\"",
+ "summary": "\"Add Corporate Location to Counterparty\"",
+ "description": "\"Add the geolocation of the counterparty's registered address\"",
+ "example_request_body": "corporateLocationJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"the view does not allow adding a corporate location\",\n \"Coordinates not possible\",\n \"Corporate Location cannot be deleted\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyCorporateLocation": {
+ "partial_function_name_raw": "\"updateCounterpartyCorporateLocation\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/corporate_location\"",
+ "summary": "\"Update Counterparty Corporate Location\"",
+ "description": "\"Update the geolocation of the counterparty's registered address\"",
+ "example_request_body": "corporateLocationJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating a corporate location\",\n \"Coordinates not possible\",\n \"Corporate Location cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyCorporateLocation": {
+ "partial_function_name_raw": "\"deleteCounterpartyCorporateLocation\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/corporate_location\"",
+ "summary": "\"Delete Counterparty Corporate Location\"",
+ "description": "\"Delete corporate location of other bank account. Delete the geolocation of the counterparty's registered address\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n \"the view does not allow metadata access\",\n \"Corporate Location cannot be deleted\",\n \"Delete not completed\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "addCounterpartyPhysicalLocation": {
+ "partial_function_name_raw": "\"addCounterpartyPhysicalLocation\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/physical_location\"",
+ "summary": "\"Add physical location to other bank account\"",
+ "description": "\"Add geocoordinates of the counterparty's main location\"",
+ "example_request_body": "physicalLocationJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow adding a physical location\",\n \"Coordinates not possible\",\n \"Physical Location cannot be added\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "updateCounterpartyPhysicalLocation": {
+ "partial_function_name_raw": "\"updateCounterpartyPhysicalLocation\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/physical_location\"",
+ "summary": "\"Update Counterparty Physical Location\"",
+ "description": "\"Update geocoordinates of the counterparty's main location\"",
+ "example_request_body": "physicalLocationJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n \"the view does not allow metadata access\",\n \"the view does not allow updating a physical location\",\n \"Coordinates not possible\",\n \"Physical Location cannot be updated\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "deleteCounterpartyPhysicalLocation": {
+ "partial_function_name_raw": "\"deleteCounterpartyPhysicalLocation\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID/metadata/physical_location\"",
+ "summary": "\"Delete Counterparty Physical Location\"",
+ "description": "\"Delete physical location of other bank account\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n NoViewPermission,\n \"Physical Location cannot be deleted\",\n \"Delete not completed\",\n UnknownError)",
+ "tags": "List(apiTagCounterpartyMetaData, apiTagCounterparty)"
+ },
+ "getTransactionsForBankAccount": {
+ "partial_function_name_raw": "\"getTransactionsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions\"",
+ "summary": "\"Get Transactions for Account (Full)\"",
+ "description": "s\"\"\"Returns transactions list of the account specified by ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).\n |\n |Authentication via OAuth is required if the view is not public.\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionsJSON",
+ "error_response_bodies": "List(BankAccountNotFound, UnknownError)",
+ "tags": "List(apiTagTransaction, apiTagAccount, apiTagPsd2, apiTagOldStyle)"
+ },
+ "getTransactionByIdForBankAccount": {
+ "partial_function_name_raw": "\"getTransactionByIdForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/transaction\"",
+ "summary": "\"Get Transaction by Id\"",
+ "description": "s\"\"\"Returns one transaction specified by TRANSACTION_ID of the account ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionJSON",
+ "error_response_bodies": "List(BankAccountNotFound, UnknownError)",
+ "tags": "List(apiTagTransaction, apiTagPsd2, apiTagOldStyle)"
+ },
+ "getTransactionNarrative": {
+ "partial_function_name_raw": "\"getTransactionNarrative\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/narrative\"",
+ "summary": "\"Get a Transaction Narrative\"",
+ "description": "\"\"\"Returns the account owner description of the transaction [moderated](#1_2_1-getViewsForBankAccount) by the view.\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionNarrativeJSON",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "addTransactionNarrative": {
+ "partial_function_name_raw": "\"addTransactionNarrative\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/narrative\"",
+ "summary": "\"Add a Transaction Narrative\"",
+ "description": "s\"\"\"Creates a description of the transaction TRANSACTION_ID.\n |\n |Note: Unlike other items of metadata, there is only one \"narrative\" per transaction accross all views.\n |If you set narrative via a view e.g. view-x it will be seen via view-y (as long as view-y has permission to see the narrative).\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\n |\"\"\"",
+ "example_request_body": "transactionNarrativeJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "updateTransactionNarrative": {
+ "partial_function_name_raw": "\"updateTransactionNarrative\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/narrative\"",
+ "summary": "\"Update a Transaction Narrative\"",
+ "description": "\"\"\"Updates the description of the transaction TRANSACTION_ID.\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "transactionNarrativeJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(InvalidJsonFormat,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "deleteTransactionNarrative": {
+ "partial_function_name_raw": "\"deleteTransactionNarrative\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/narrative\"",
+ "summary": "\"Delete a Transaction Narrative\"",
+ "description": "\"\"\"Deletes the description of the transaction TRANSACTION_ID.\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n NoViewPermission,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "getCommentsForViewOnTransaction": {
+ "partial_function_name_raw": "\"getCommentsForViewOnTransaction\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/comments\"",
+ "summary": "\"Get Transaction Comments\"",
+ "description": "\"\"\"Returns the transaction TRANSACTION_ID comments made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionCommentsJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "addCommentForViewOnTransaction": {
+ "partial_function_name_raw": "\"addCommentForViewOnTransaction\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/comments\"",
+ "summary": "\"Add a Transaction Comment\"",
+ "description": "\"\"\"Posts a comment about a transaction TRANSACTION_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID.\n |\n |${authenticationRequiredMessage(false)}\n |\n |Authentication is required since the comment is linked with the user.\"\"\"",
+ "example_request_body": "postTransactionCommentJSON",
+ "success_response_body": "transactionCommentJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "deleteCommentForViewOnTransaction": {
+ "partial_function_name_raw": "\"deleteCommentForViewOnTransaction\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/comments/COMMENT_ID\"",
+ "summary": "\"Delete a Transaction Comment\"",
+ "description": "\"\"\"Delete the comment COMMENT_ID about the transaction TRANSACTION_ID made on [view](#1_2_1-getViewsForBankAccount).\n |\n |Authentication via OAuth is required. The user must either have owner privileges for this account, or must be the user that posted the comment.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n AuthenticatedUserIsRequired,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "getTagsForViewOnTransaction": {
+ "partial_function_name_raw": "\"getTagsForViewOnTransaction\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/tags\"",
+ "summary": "\"Get Transaction Tags\"",
+ "description": "\"\"\"Returns the transaction TRANSACTION_ID tags made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionTagJSON",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "addTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"addTagForViewOnTransaction\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/tags\"",
+ "summary": "\"Add a Transaction Tag\"",
+ "description": "s\"\"\"Posts a tag about a transaction TRANSACTION_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |Authentication is required as the tag is linked with the user.\"\"\"",
+ "example_request_body": "postTransactionTagJSON",
+ "success_response_body": "transactionTagJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "deleteTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"deleteTagForViewOnTransaction\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/tags/TAG_ID\"",
+ "summary": "\"Delete a Transaction Tag\"",
+ "description": "\"\"\"Deletes the tag TAG_ID about the transaction TRANSACTION_ID made on [view](#1_2_1-getViewsForBankAccount).\n |Authentication via OAuth is required. The user must either have owner privileges for this account, \n |or must be the user that posted the tag.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "getImagesForViewOnTransaction": {
+ "partial_function_name_raw": "\"getImagesForViewOnTransaction\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/images\"",
+ "summary": "\"Get Transaction Images\"",
+ "description": "\"\"\"Returns the transaction TRANSACTION_ID images made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionImagesJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "addImageForViewOnTransaction": {
+ "partial_function_name_raw": "\"addImageForViewOnTransaction\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/images\"",
+ "summary": "\"Add a Transaction Image\"",
+ "description": "s\"\"\"Posts an image about a transaction TRANSACTION_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID.\n |\n |${userAuthenticationMessage(true) }\n |\n |The image is linked with the user.\"\"\"",
+ "example_request_body": "postTransactionImageJSON",
+ "success_response_body": "transactionImageJSON",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n InvalidUrl,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "deleteImageForViewOnTransaction": {
+ "partial_function_name_raw": "\"deleteImageForViewOnTransaction\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/images/IMAGE_ID\"",
+ "summary": "\"Delete a Transaction Image\"",
+ "description": "\"\"\"Deletes the image IMAGE_ID about the transaction TRANSACTION_ID made on [view](#1_2_1-getViewsForBankAccount).\n |\n |Authentication via OAuth is required. The user must either have owner privileges for this account, or must be the user that posted the image.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n BankAccountNotFound,\n NoViewPermission,\n AuthenticatedUserIsRequired,\n \"You must be able to see images in order to delete them\",\n \"Image not found for this transaction\",\n \"Deleting images not permitted for this view\",\n \"Deleting images not permitted for the current user\",\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "getWhereTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"getWhereTagForViewOnTransaction\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/where\"",
+ "summary": "\"Get a Transaction where Tag\"",
+ "description": "\"\"\"Returns the \"where\" Geo tag added to the transaction TRANSACTION_ID made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n |It represents the location where the transaction has been initiated.\n |\n |Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionWhereJSON",
+ "error_response_bodies": "List(BankAccountNotFound,\n NoViewPermission,\n ViewNotFound,\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "addWhereTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"addWhereTagForViewOnTransaction\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/where\"",
+ "summary": "\"Add a Transaction where Tag\"",
+ "description": "s\"\"\"Creates a \"where\" Geo tag on a transaction TRANSACTION_ID in a [view](#1_2_1-getViewsForBankAccount).\n |\n |${userAuthenticationMessage(true)}\n |\n |The geo tag is linked with the user.\"\"\"",
+ "example_request_body": "postTransactionWhereJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n ViewNotFound,\n NoViewPermission,\n \"Coordinates not possible\",\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "updateWhereTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"updateWhereTagForViewOnTransaction\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/where\"",
+ "summary": "\"Update a Transaction where Tag\"",
+ "description": "s\"\"\"Updates the \"where\" Geo tag on a transaction TRANSACTION_ID in a [view](#1_2_1-getViewsForBankAccount).\n |\n |${userAuthenticationMessage(true)}\n |\n |The geo tag is linked with the user.\"\"\"",
+ "example_request_body": "postTransactionWhereJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n InvalidJsonFormat,\n ViewNotFound,\n NoViewPermission,\n \"Coordinates not possible\",\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "deleteWhereTagForViewOnTransaction": {
+ "partial_function_name_raw": "\"deleteWhereTagForViewOnTransaction\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/metadata/where\"",
+ "summary": "\"Delete a Transaction Tag\"",
+ "description": "s\"\"\"Deletes the where tag of the transaction TRANSACTION_ID made on [view](#1_2_1-getViewsForBankAccount).\n |\n |${userAuthenticationMessage(true)}\n |\n |The user must either have owner privileges for this account, or must be the user that posted the geo tag.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n NoViewPermission,\n AuthenticatedUserIsRequired,\n ViewNotFound,\n \"there is no tag to delete\",\n \"Delete not completed\",\n UnknownError)",
+ "tags": "List(apiTagTransactionMetaData, apiTagTransaction)"
+ },
+ "getOtherAccountForTransaction": {
+ "partial_function_name_raw": "\"getOtherAccountForTransaction\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/other_account\"",
+ "summary": "\"Get Other Account of Transaction\"",
+ "description": "\"\"\"Get other account of a transaction.\n |Returns details of the other party involved in the transaction, moderated by the [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n Authentication via OAuth is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountJSON",
+ "error_response_bodies": "List(BankAccountNotFound, UnknownError)",
+ "tags": "List(apiTagTransaction, apiTagCounterparty)"
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v1_3_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v1_3_0.json
new file mode 100644
index 0000000000..1585c68286
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v1_3_0.json
@@ -0,0 +1,45 @@
+{
+ "schema_version": 1,
+ "version": "v1_3_0",
+ "source_file": "obp-api/src/main/scala/code/api/v1_3_0/APIMethods130.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 3,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getCards": {
+ "partial_function_name_raw": "\"getCards\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/cards\"",
+ "summary": "\"Get cards for the current user\"",
+ "description": "\"Returns data about all the physical cards a user has been issued. These could be debit cards, credit cards, etc.\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "physicalCardsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagCard)"
+ },
+ "getCardsForBank": {
+ "partial_function_name_raw": "\"getCardsForBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/cards\"",
+ "summary": "\"Get cards for the specified bank\"",
+ "description": "\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "physicalCardsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,BankNotFound, UnknownError)",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCardsForBank))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v1_4_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v1_4_0.json
new file mode 100644
index 0000000000..5c47fd3aea
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v1_4_0.json
@@ -0,0 +1,122 @@
+{
+ "schema_version": 1,
+ "version": "v1_4_0",
+ "source_file": "obp-api/src/main/scala/code/api/v1_4_0/APIMethods140.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 10,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getCustomer": {
+ "partial_function_name_raw": "\"getCustomer\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customer\"",
+ "summary": "\"Get customer for logged in user\"",
+ "description": "\"\"\"Information about the currently authenticated user.\n |\n |Authentication via OAuth is required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJsonV140",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagCustomer, apiTagOldStyle)"
+ },
+ "getCustomersMessages": {
+ "partial_function_name_raw": "\"getCustomersMessages\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customer/messages\"",
+ "summary": "\"Get Customer Messages for all Customers\"",
+ "description": "\"\"\"Get messages for the logged in customer\n |Messages sent to the currently authenticated user.\n |\n |Authentication via OAuth is required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerMessagesJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagMessage, apiTagCustomer)"
+ },
+ "addCustomerMessage": {
+ "partial_function_name_raw": "nameOf(addCustomerMessage)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customer/CUSTOMER_ID/messages\"",
+ "summary": "\"Create Customer Message\"",
+ "description": "\"Create a message for the customer specified by CUSTOMER_ID\"",
+ "example_request_body": "addCustomerMessageJson",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagMessage, apiTagCustomer, apiTagPerson)"
+ },
+ "getBranches": {
+ "partial_function_name_raw": "\"getBranches\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/branches\"",
+ "summary": "\"Get Bank Branches\"",
+ "description": "s\"\"\"Returns information about branches for a single bank specified by BANK_ID including:\n |\n |* Name\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n ${urlParametersDocument(false, false)}\n |\n |You can use the url query parameters *limit* and *offset* for pagination\n |\n |${userAuthenticationMessage(!getBranchesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "branchesJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n \"No branches available. License may not be set.\",\n UnknownError)",
+ "tags": "List(apiTagBranch, apiTagOldStyle)"
+ },
+ "getAtms": {
+ "partial_function_name_raw": "\"getAtms\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Get Bank ATMS\"",
+ "description": "s\"\"\"Returns information about ATMs for a single bank specified by BANK_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |\n |${urlParametersDocument(false,false)}\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmsJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n \"No ATMs available. License may not be set.\",\n UnknownError)",
+ "tags": "List(apiTagBank, apiTagOldStyle)"
+ },
+ "getProducts": {
+ "partial_function_name_raw": "\"getProducts\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Get Bank Products\"",
+ "description": "s\"\"\"Returns information about the financial products offered by a bank specified by BANK_ID including:\n |\n |* Name\n |* Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n \"No products available.\",\n \"License may not be set.\",\n UnknownError)",
+ "tags": "List(apiTagBank, apiTagOldStyle)"
+ },
+ "getCrmEvents": {
+ "partial_function_name_raw": "\"getCrmEvents\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/crm-events\"",
+ "summary": "\"Get CRM Events\"",
+ "description": "\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "crmEventsJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n \"No CRM Events available.\",\n UnknownError)",
+ "tags": "List(apiTagCustomer)"
+ },
+ "getTransactionRequestTypes": {
+ "partial_function_name_raw": "\"getTransactionRequestTypes\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types\"",
+ "summary": "\"Get Transaction Request Types for Account\"",
+ "description": "\"\"\"Returns the Transaction Request Types that the account specified by ACCOUNT_ID and view specified by VIEW_ID has access to.\n |\n |These are the ways this API Server can create a Transaction via a Transaction Request\n |(as opposed to Transaction Types which include external types too e.g. for Transactions created by core banking etc.)\n |\n | A Transaction Request Type internally determines:\n |\n | * the required Transaction Request 'body' i.e. fields that define the 'what' and 'to' of a Transaction Request,\n | * the type of security challenge that may be be raised before the Transaction Request proceeds, and\n | * the threshold of that challenge.\n |\n | For instance in a 'SANDBOX_TAN' Transaction Request, for amounts over 1000 currency units, the user must supply a positive integer to complete the Transaction Request and create a Transaction.\n |\n | This approach aims to provide only one endpoint for initiating transactions, and one that handles challenges, whilst still allowing flexibility with the payload and internal logic.\n | \n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestTypesJsonV140",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n AccountNotFound,\n \"Please specify a valid value for CURRENCY of your Bank Account. \"\n ,\"Current user does not have access to the view \",\n \"account not found at bank\",\n \"user does not have access to owner view\",\n TransactionRequestsNotEnabled,\n UnknownError)",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "addCustomer": {
+ "partial_function_name_raw": "\"addCustomer\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customer\"",
+ "summary": "\"Add a customer.\"",
+ "description": "s\"\"\"Add a customer linked to the currently authenticated user.\n |The Customer resource stores the customer number, legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |This call may require additional permissions/role in the future.\n |For now the authenticated user can create at most one linked customer.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |${userAuthenticationMessage(true) }\n |Note: This call is depreciated in favour of v.2.0.0 createCustomer\n |\"\"\"",
+ "example_request_body": "code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createCustomerJson",
+ "success_response_body": "customerJsonV140",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n \"entitlements required\",\n CustomerNumberAlreadyExists,\n \"Problem getting user_id\",\n UserNotFoundById,\n \"Could not create customer\",\n \"Could not create user_customer_links\",\n UnknownError)",
+ "tags": "List(apiTagCustomer, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer, canCreateUserCustomerLink))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v2_0_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v2_0_0.json
new file mode 100644
index 0000000000..9c4a2265a8
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v2_0_0.json
@@ -0,0 +1,476 @@
+{
+ "schema_version": 1,
+ "version": "v2_0_0",
+ "source_file": "obp-api/src/main/scala/code/api/v2_0_0/APIMethods200.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 37,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getPrivateAccountsAllBanks": {
+ "partial_function_name_raw": "\"getPrivateAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/accounts\"",
+ "summary": "\"Get all Accounts at all Banks\"",
+ "description": "s\"\"\"Get all accounts at all banks the User has access to.\n |Returns the list of accounts at that the user has access to at all banks.\n |For each account the API returns the account ID and the available views.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPublicData, apiTagOldStyle)"
+ },
+ "corePrivateAccountsAllBanks": {
+ "partial_function_name_raw": "\"corePrivateAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/accounts\"",
+ "summary": "\"Get Accounts at all Banks (Private)\"",
+ "description": "s\"\"\"Get private accounts at all banks (Authenticated access)\n |Returns the list of accounts containing private views for the user at all banks.\n |For each account the API returns the ID and the available views.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsJSON",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPsd2, apiTagOldStyle)"
+ },
+ "publicAccountsAllBanks": {
+ "partial_function_name_raw": "\"publicAccountsAllBanks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/accounts/public\"",
+ "summary": "\"Get Public Accounts at all Banks\"",
+ "description": "s\"\"\"Get public accounts at all banks (Anonymous access).\n |Returns accounts that contain at least one public view (a view where is_public is true)\n |For each account the API returns the ID and the available views.\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CannotGetAccounts, UnknownError)",
+ "tags": "List(apiTagAccountPublic, apiTagAccount, apiTagPublicData)"
+ },
+ "getPrivateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"getPrivateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts\"",
+ "summary": "\"Get Accounts at Bank\"",
+ "description": "s\"\"\"\n |Returns the list of accounts at BANK_ID that the user has access to.\n |For each account the API returns the account ID and the views available to the user..\n |Each account must have at least one private View.\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List(BankNotFound, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPublicData)"
+ },
+ "corePrivateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"corePrivateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts\"",
+ "summary": "\"Get Accounts at Bank (Private)\"",
+ "description": "s\"\"\"Get private accounts at one bank (Authenticated access).\n |Returns the list of accounts containing private views for the user at BANK_ID.\n |For each account the API returns the ID and label. To also see the list of Views, see privateAccountsAtOneBank\n |\n |\n |This call MAY have an alias /bank/accounts but ONLY if defaultBank is set in Props\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPsd2)"
+ },
+ "privateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"privateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/private\"",
+ "summary": "\"Get private accounts at one bank\"",
+ "description": "s\"\"\"Returns the list of private accounts at BANK_ID that the user has access to.\n |For each account the API returns the ID and the available views.\n |\n |If you want to see more information on the Views, use the Account Detail call.\n |If you want less information about the account, use the /my accounts call\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPsd2)"
+ },
+ "publicAccountsAtOneBank": {
+ "partial_function_name_raw": "\"publicAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/public\"",
+ "summary": "\"Get Public Accounts at Bank\"",
+ "description": "s\"\"\"Returns a list of the public accounts (Anonymous access) at BANK_ID. For each account the API returns the ID and the available views.\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagAccountPublic, apiTagAccount, apiTagPublicData)"
+ },
+ "getKycDocuments": {
+ "partial_function_name_raw": "\"getKycDocuments\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers/CUSTOMER_ID/kyc_documents\"",
+ "summary": "\"Get Customer KYC Documents\"",
+ "description": "s\"\"\"Get KYC (know your customer) documents for a customer specified by CUSTOMER_ID\n |Get a list of documents that affirm the identity of the customer\n |Passport, driving licence etc.\n |${userAuthenticationMessage(false)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "kycDocumentsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CustomerNotFoundByCustomerId, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyKycDocuments))"
+ }
+ },
+ "getKycMedia": {
+ "partial_function_name_raw": "\"getKycMedia\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers/CUSTOMER_ID/kyc_media\"",
+ "summary": "\"Get KYC Media for a customer\"",
+ "description": "s\"\"\"Get KYC media (scans, pictures, videos) that affirms the identity of the customer.\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "kycMediasJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CustomerNotFoundByCustomerId, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyKycMedia))"
+ }
+ },
+ "getKycChecks": {
+ "partial_function_name_raw": "\"getKycChecks\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers/CUSTOMER_ID/kyc_checks\"",
+ "summary": "\"Get Customer KYC Checks\"",
+ "description": "s\"\"\"Get KYC checks for the Customer specified by CUSTOMER_ID.\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "kycChecksJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CustomerNotFoundByCustomerId, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyKycChecks))"
+ }
+ },
+ "getKycStatuses": {
+ "partial_function_name_raw": "\"getKycStatuses\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers/CUSTOMER_ID/kyc_statuses\"",
+ "summary": "\"Get Customer KYC statuses\"",
+ "description": "s\"\"\"Get the KYC statuses for a customer specified by CUSTOMER_ID over time.\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "kycStatusesJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CustomerNotFoundByCustomerId, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyKycStatuses))"
+ }
+ },
+ "getSocialMediaHandles": {
+ "partial_function_name_raw": "\"getSocialMediaHandles\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/social_media_handles\"",
+ "summary": "\"Get Customer Social Media Handles\"",
+ "description": "s\"\"\"Get social media handles for a customer specified by CUSTOMER_ID.\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "socialMediasJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, CustomerNotFoundByCustomerId, UnknownError)",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSocialMediaHandles))"
+ }
+ },
+ "addKycDocument": {
+ "partial_function_name_raw": "\"addKycDocument\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/kyc_documents/KYC_DOCUMENT_ID\"",
+ "summary": "\"Add KYC Document\"",
+ "description": "\"Add a KYC document for the customer specified by CUSTOMER_ID. KYC Documents contain the document type (e.g. passport), place of issue, expiry etc. \"",
+ "example_request_body": "postKycDocumentJSON",
+ "success_response_body": "kycDocumentJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, InvalidJsonFormat, BankNotFound, CustomerNotFoundByCustomerId,\"Server error: could not add KycDocument\", UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddKycDocument))"
+ }
+ },
+ "addKycMedia": {
+ "partial_function_name_raw": "\"addKycMedia\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/kyc_media/KYC_MEDIA_ID\"",
+ "summary": "\"Add KYC Media\"",
+ "description": "\"Add some KYC media for the customer specified by CUSTOMER_ID. KYC Media resources relate to KYC Documents and KYC Checks and contain media urls for scans of passports, utility bills etc\"",
+ "example_request_body": "postKycMediaJSON",
+ "success_response_body": "kycMediaJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, InvalidJsonFormat, CustomerNotFoundByCustomerId, ServerAddDataError, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddKycMedia))"
+ }
+ },
+ "addKycCheck": {
+ "partial_function_name_raw": "\"addKycCheck\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/kyc_check/KYC_CHECK_ID\"",
+ "summary": "\"Add KYC Check\"",
+ "description": "\"Add a KYC check for the customer specified by CUSTOMER_ID. KYC Checks store details of checks on a customer made by the KYC team, their comments and a satisfied status\"",
+ "example_request_body": "postKycCheckJSON",
+ "success_response_body": "kycCheckJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, InvalidJsonFormat, BankNotFound, CustomerNotFoundByCustomerId, ServerAddDataError, UnknownError)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddKycCheck))"
+ }
+ },
+ "addKycStatus": {
+ "partial_function_name_raw": "\"addKycStatus\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/kyc_statuses\"",
+ "summary": "\"Add KYC Status\"",
+ "description": "\"Add a kyc_status for the customer specified by CUSTOMER_ID. KYC Status is a timeline of the KYC status of the customer\"",
+ "example_request_body": "postKycStatusJSON",
+ "success_response_body": "kycStatusJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, InvalidJsonFormat, InvalidBankIdFormat,UnknownError, BankNotFound ,ServerAddDataError ,CustomerNotFoundByCustomerId)",
+ "tags": "List(apiTagKyc, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddKycStatus))"
+ }
+ },
+ "addSocialMediaHandle": {
+ "partial_function_name_raw": "\"addSocialMediaHandle\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/social_media_handles\"",
+ "summary": "\"Create Customer Social Media Handle\"",
+ "description": "\"Create a customer social media handle for the customer specified by CUSTOMER_ID\"",
+ "example_request_body": "socialMediaJSON",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidBankIdFormat,\n UserHasMissingRoles,\n CustomerNotFoundByCustomerId,\n UnknownError)",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddSocialMediaHandle))"
+ }
+ },
+ "getCoreAccountById": {
+ "partial_function_name_raw": "\"getCoreAccountById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/account\"",
+ "summary": "\"Get Account by Id (Core)\"",
+ "description": "s\"\"\"Information returned about the account specified by ACCOUNT_ID:\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |\n |This call returns the owner view and requires access to that view.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountJSON",
+ "error_response_bodies": "List(BankAccountNotFound,UnknownError)",
+ "tags": "apiTagAccount :: apiTagPsd2 :: apiTagOldStyle :: Nil"
+ },
+ "getCoreTransactionsForBankAccount": {
+ "partial_function_name_raw": "\"getCoreTransactionsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/transactions\"",
+ "summary": "\"Get Transactions for Account (Core)\"",
+ "description": "s\"\"\"Returns transactions list (Core info) of the account specified by ACCOUNT_ID.\n |\n |Authentication is required.\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreTransactionsJSON",
+ "error_response_bodies": "List(BankAccountNotFound, UnknownError)",
+ "tags": "List(apiTagTransaction, apiTagAccount, apiTagPsd2, apiTagOldStyle)"
+ },
+ "accountById": {
+ "partial_function_name_raw": "\"accountById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Account by Id (Full)\"",
+ "description": "s\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |* Available views (sorted by short_name)\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |${userAuthenticationMessage(true)} if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedAccountJSON",
+ "error_response_bodies": "List(BankNotFound,AccountNotFound,ViewNotFound, UserNoPermissionAccessView, UnknownError)",
+ "tags": "apiTagAccount :: apiTagOldStyle :: Nil"
+ },
+ "getPermissionsForBankAccount": {
+ "partial_function_name_raw": "\"getPermissionsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions\"",
+ "summary": "\"Get access\"",
+ "description": "s\"\"\"Returns the list of the permissions at BANK_ID for account ACCOUNT_ID, with each time a pair composed of the user and the views that he has access to.\n |\n |${userAuthenticationMessage(true)}\n |and the user needs to have access to the owner view.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "permissionsJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, AccountNotFound ,UnknownError)",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagEntitlement)"
+ },
+ "getPermissionForUserForBankAccount": {
+ "partial_function_name_raw": "\"getPermissionForUserForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID\"",
+ "summary": "\"Get Account access for User\"",
+ "description": "s\"\"\"Returns the list of the views at BANK_ID for account ACCOUNT_ID that a user identified by PROVIDER_ID at their provider PROVIDER has access to.\n |All url parameters must be [%-encoded](http://en.wikipedia.org/wiki/Percent-encoding), which is often especially relevant for USER_ID and PROVIDER.\n |\n |${userAuthenticationMessage(true)}\n |\n |The user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJSONV121",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,BankNotFound, AccountNotFound,UnknownError)",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser, apiTagOldStyle)"
+ },
+ "createAccount": {
+ "partial_function_name_raw": "\"createAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Create Account\"",
+ "description": "\"\"\"Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.\n |\n |\n |The User can create an Account for themself or an Account for another User if they have CanCreateAccount role.\n |\n |If USER_ID is not specified the account will be owned by the logged in User.\n |\n |ACCOUNT_ID SHOULD be a UUID. ACCOUNT_ID MUST NOT be the ACCOUNT_NUMBER.\n |\n |TYPE SHOULD be the PRODUCT_CODE from Product.\n |\n |Note: The Amount must be zero.\"\"\".stripMargin",
+ "example_request_body": "CreateAccountJSON(\"A user_id\",\"CURRENT\", \"Label\", AmountOfMoneyJSON121(\"EUR\", \"0\"))",
+ "success_response_body": "coreAccountJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidUserId,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n UserNotFoundById,\n InvalidAccountBalanceAmount,\n InvalidAccountType,\n InvalidAccountInitialBalance,\n InvalidAccountBalanceCurrency,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccount))"
+ }
+ },
+ "getTransactionTypes": {
+ "partial_function_name_raw": "\"getTransactionTypes\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/transaction-types\"",
+ "summary": "\"Get Transaction Types at Bank\"",
+ "description": "s\"\"\"Get Transaction Types for the bank specified by BANK_ID:\n |\n |Lists the possible Transaction Types available at the bank (as opposed to Transaction Request Types which are the possible ways Transactions can be created by this API Server).\n |\n | * id : Unique transaction type id across the API instance. SHOULD be a UUID. MUST be unique.\n | * bank_id : The bank that supports this TransactionType\n | * short_code : A short code (SHOULD have no-spaces) which MUST be unique across the bank. May be stored with Transactions to link here\n | * summary : A succinct summary\n | * description : A longer description\n | * charge : The charge to the customer for each one of these\n |\n |${userAuthenticationMessage(!getTransactionTypesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionTypesJsonV200",
+ "error_response_bodies": "List(BankNotFound, UnknownError)",
+ "tags": "List(apiTagBank, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "createUser": {
+ "partial_function_name_raw": "\"createUser\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Create User\"",
+ "description": "s\"\"\"Creates OBP user.\n | No authorisation required.\n |\n | Mimics current webform to Register.\n |\n | Requires username(email), password, first_name, last_name, and email.\n |\n | Validation checks performed:\n | - Password must meet strong password requirements (InvalidStrongPasswordFormat error if not)\n | - Username must be unique (409 error if username already exists)\n | - All required fields must be present in valid JSON format\n |\n | Email validation behavior:\n | - Controlled by property 'authUser.skipEmailValidation' (default: false)\n | - When false: User is created with validated=false and a validation email is sent to the user's email address\n | - When true: User is created with validated=true and no validation email is sent\n | - Default entitlements are granted immediately regardless of validation status\n |\n | Note: If email validation is required (skipEmailValidation=false), the user must click the validation link\n | in the email before they can log in, even though entitlements are already granted.\n |\n |\"\"\"",
+ "example_request_body": "createUserJson",
+ "success_response_body": "userJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, InvalidJsonFormat, InvalidStrongPasswordFormat, DuplicateUsername, ExternalUserCheckFailed, \"Error occurred during user creation.\", UnknownError)",
+ "tags": "List(apiTagUser, apiTagOnboarding)"
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "\"createCustomer\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"Add a customer linked to the user specified by user_id\n |The Customer resource stores the customer number, legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |This call may require additional permissions/role in the future.\n |For now the authenticated user can create at most one linked customer.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "createCustomerJson",
+ "success_response_body": "customerJsonV140",
+ "error_response_bodies": "List(\n InvalidBankIdFormat,\n AuthenticatedUserIsRequired,\n BankNotFound,\n CustomerNumberAlreadyExists,\n UserHasMissingRoles,\n UserNotFoundById,\n CreateConsumerError,\n CustomerAlreadyExistsForUser,\n CreateUserCustomerLinksError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer,canCreateUserCustomerLink))"
+ }
+ },
+ "getCurrentUser": {
+ "partial_function_name_raw": "\"getCurrentUser\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current\"",
+ "summary": "\"Get User (Current)\"",
+ "description": "\"\"\"Get the logged in user\n |\n |Login is required.\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagUser, apiTagOldStyle)"
+ },
+ "getUser": {
+ "partial_function_name_raw": "\"getUser\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_EMAIL\"",
+ "summary": "\"Get Users by Email Address\"",
+ "description": "\"\"\"Get users by email address\n |\n |Login is required.\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundByEmail, UnknownError)",
+ "tags": "List(apiTagUser, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "createUserCustomerLinks": {
+ "partial_function_name_raw": "\"createUserCustomerLinks\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/user_customer_links\"",
+ "summary": "\"Create User Customer Link\"",
+ "description": "s\"\"\"Link a User to a Customer\n |\n |${userAuthenticationMessage(true)}\n |\n |$createUserCustomerLinksrequiredEntitlementsText\n |\"\"\"",
+ "example_request_body": "createUserCustomerLinkJson",
+ "success_response_body": "userCustomerLinkJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n BankNotFound,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n CustomerAlreadyExistsForUser,\n CreateUserCustomerLinksError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateUserCustomerLink,canCreateUserCustomerLinkAtAnyBank))"
+ }
+ },
+ "addEntitlement": {
+ "partial_function_name_raw": "\"addEntitlement\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/entitlements\"",
+ "summary": "\"Add Entitlement for a User\"",
+ "description": "\"\"\"Create Entitlement. Grant Role to User.\n |\n |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views)\n |\n |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. \"bank_id\":\"\"\n |\n |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. \"bank_id\":\"my-bank-id\"\n |\n |Authentication is required and the user needs to be a Super Admin. Super Admins are listed in the Props file.\"\"\"",
+ "example_request_body": "code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createEntitlementJSON",
+ "success_response_body": "entitlementJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserNotFoundById,\n UserNotSuperAdmin,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementIsBankRole,\n EntitlementIsSystemRole,\n EntitlementAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateEntitlementAtOneBank,canCreateEntitlementAtAnyBank))"
+ }
+ },
+ "getEntitlements": {
+ "partial_function_name_raw": "\"getEntitlements\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/entitlements\"",
+ "summary": "\"Get Entitlements for User\"",
+ "description": "s\"\"\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementJSONs",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyUserAtAnyBank))"
+ }
+ },
+ "deleteEntitlement": {
+ "partial_function_name_raw": "\"deleteEntitlement\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/entitlement/ENTITLEMENT_ID\"",
+ "summary": "\"Delete Entitlement\"",
+ "description": "\"\"\"Delete Entitlement specified by ENTITLEMENT_ID for an user specified by USER_ID\n |\n |Authentication is required and the user needs to be a Super Admin.\n |Super Admins are listed in the Props file.\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, EntitlementNotFound, UnknownError)",
+ "tags": "List(apiTagRole, apiTagUser, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteEntitlementAtAnyBank))"
+ }
+ },
+ "getAllEntitlements": {
+ "partial_function_name_raw": "\"getAllEntitlements\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/entitlements\"",
+ "summary": "\"Get all Entitlements\"",
+ "description": "\"\"\"\n |\n |Login is required.\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementJSONs",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyUserAtAnyBank))"
+ }
+ },
+ "elasticSearchWarehouse": {
+ "partial_function_name_raw": "\"elasticSearchWarehouse\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/search/warehouse\"",
+ "summary": "\"Search Warehouse Data Via Elasticsearch\"",
+ "description": "\"\"\"\n |Search warehouse data via Elastic Search.\n |\n |Login is required.\n |\n |CanSearchWarehouse entitlement is required to search warehouse data!\n |\n |Send your email, name, project name and user_id to the admins to get access.\n |\n |Elastic (search) is used in the background. See links below for syntax.\n |\n |\n |parameters:\n |\n | esType - elasticsearch type\n |\n | simple query:\n |\n | q - plain_text_query\n |\n | df - default field to search\n |\n | sort - field to sort on\n |\n | size - number of hits returned, default 10\n |\n | from - show hits starting from\n |\n | json query:\n |\n | source - JSON_query_(URL-escaped)\n |\n |\n |Example usage:\n |\n |GET /search/warehouse/q=findThis\n |\n |or:\n |\n |GET /search/warehouse/source={\"query\":{\"query_string\":{\"query\":\"findThis\"}}}\n |\n |\n |Note!!\n |\n |The whole JSON query string MUST be URL-encoded:\n |\n |* For { use %7B\n |* For } use %7D\n |* For : use %3A\n |* For \" use %22\n |\n |etc..\n |\n |\n |\n |Only q, source and esType are passed to Elastic\n |\n |Elastic simple query: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html\n |\n |Elastic JSON query: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html\n |\n |You can specify the esType thus: /search/warehouse/esType=type&q=a\n |\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "emptyElasticSearch",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagSearchWarehouse, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canSearchWarehouse))"
+ }
+ },
+ "elasticSearchMetrics": {
+ "partial_function_name_raw": "\"elasticSearchMetrics\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/search/metrics\"",
+ "summary": "\"Search API Metrics via Elasticsearch\"",
+ "description": "\"\"\"\n |Search the API calls made to this API instance via Elastic Search.\n |\n |Login is required.\n |\n |CanSearchMetrics entitlement is required to search metrics data.\n |\n |\n |parameters:\n |\n | esType - elasticsearch type\n |\n | simple query:\n |\n | q - plain_text_query\n |\n | df - default field to search\n |\n | sort - field to sort on\n |\n | size - number of hits returned, default 10\n |\n | from - show hits starting from\n |\n | json query:\n |\n | source - JSON_query_(URL-escaped)\n |\n |\n |example usage:\n |\n | /search/metrics/q=findThis\n |\n |or:\n |\n | /search/metrics/source={\"query\":{\"query_string\":{\"query\":\"findThis\"}}}\n |\n |\n |Note!!\n |\n |The whole JSON query string MUST be URL-encoded:\n |\n |* For { use %7B\n |* For } use %7D\n |* For : use %3A\n |* For \" use %22\n |\n |etc..\n |\n |\n |\n |Only q, source and esType are passed to Elastic\n |\n |Elastic simple query: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html\n |\n |Elastic JSON query: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html\n |\n |\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "emptyElasticSearch",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagMetric, apiTagApi, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canSearchMetrics))"
+ }
+ },
+ "getCustomers": {
+ "partial_function_name_raw": "\"getCustomers\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/customers\"",
+ "summary": "\"Get all customers for logged in user\"",
+ "description": "\"\"\"Information about the currently authenticated user.\n |\n |Authentication via OAuth is required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersJsonV140",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserCustomerLinksNotFoundForUser, UnknownError)",
+ "tags": "List(apiTagPerson, apiTagCustomer, apiTagOldStyle)"
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v2_1_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v2_1_0.json
new file mode 100644
index 0000000000..bbd2b1fbf8
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v2_1_0.json
@@ -0,0 +1,359 @@
+{
+ "schema_version": 1,
+ "version": "v2_1_0",
+ "source_file": "obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 28,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "sandboxDataImport": {
+ "partial_function_name_raw": "\"sandboxDataImport\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/sandbox/data-import\"",
+ "summary": "\"Create sandbox\"",
+ "description": "s\"\"\"Import bulk data into the sandbox (Authenticated access).\n |\n |This call can be used to create banks, users, accounts and transactions which are stored in the local RDBMS.\n |\n |The user needs to have CanCreateSandbox entitlement.\n |\n |Note: This is a monolithic call. You could also use a combination of endpoints including create bank, create user, create account and create transaction request to create similar data.\n |\n |An example of an import set of data (json) can be found [here](https://raw.githubusercontent.com/OpenBankProject/OBP-API/develop/obp-api/src/main/scala/code/api/sandbox/example_data/2016-04-28/example_import.json)\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "SandboxData.importJson",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n DataImportDisabled,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSandbox)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSandbox))"
+ }
+ },
+ "getTransactionRequestTypesSupportedByBank": {
+ "partial_function_name_raw": "\"getTransactionRequestTypesSupportedByBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/transaction-request-types\"",
+ "summary": "\"Get Transaction Request Types at Bank\"",
+ "description": "s\"\"\"Get the list of the Transaction Request Types supported by the bank.\n |\n |${userAuthenticationMessage(!getTransactionRequestTypesIsPublic)}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestTypesJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagTransactionRequest, apiTagBank)"
+ },
+ "createTransactionRequestSandboxTan": {
+ "partial_function_name_raw": "\"createTransactionRequestSandboxTan\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SANDBOX_TAN/transaction-requests\"",
+ "summary": "\"Create Transaction Request (SANDBOX_TAN)\"",
+ "description": "s\"\"\"When using SANDBOX_TAN, the payee is set in the request body.\n |\n |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyJsonV200",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n ViewNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n UserNoPermissionAccessView,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestCounterparty": {
+ "partial_function_name_raw": "\"createTransactionRequestCounterparty\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/COUNTERPARTY/transaction-requests\"",
+ "summary": "\"Create Transaction Request (COUNTERPARTY)\"",
+ "description": "s\"\"\"\n |Special instructions for COUNTERPARTY:\n |\n |When using a COUNTERPARTY to create a Transaction Request, specificy the counterparty_id in the body of the request.\n |The routing details of the counterparty will be forwarded for the transfer.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyCounterpartyJSON",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n ViewNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n UserNoPermissionAccessView,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestSepa": {
+ "partial_function_name_raw": "\"createTransactionRequestSepa\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SEPA/transaction-requests\"",
+ "summary": "\"Create Transaction Request (SEPA)\"",
+ "description": "s\"\"\"\n |Special instructions for SEPA:\n |\n |When using a SEPA Transaction Request, you specify the IBAN of a Counterparty in the body of the request.\n |The routing details (IBAN) of the counterparty will be forwarded to the core banking system for the transfer.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodySEPAJSON",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n ViewNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n UserNoPermissionAccessView,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestFreeForm": {
+ "partial_function_name_raw": "\"createTransactionRequestFreeForm\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/FREE_FORM/transaction-requests\"",
+ "summary": "\"Create Transaction Request (FREE_FORM).\"",
+ "description": "s\"\"\"$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyFreeFormJSON",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n ViewNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n UserNoPermissionAccessView,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAnyTransactionRequest))"
+ }
+ },
+ "answerTransactionRequestChallenge": {
+ "partial_function_name_raw": "\"answerTransactionRequestChallenge\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge\"",
+ "summary": "\"Answer Transaction Request Challenge\"",
+ "description": "\"\"\"In Sandbox mode, any string that can be converted to a positive integer will be accepted as an answer.\n |\n |This endpoint expects the following data as provided in the createTransactionRequest response body:\n |\n |1)`TRANSACTION_REQUEST_TYPE` : as per the selected createTransactionRequest type, part of the request URL.\n |\n |2)`TRANSACTION_REQUEST_ID` : the value of the `id` field of the createTransactionRequest response body.\n |\n |3) `id` : the value of `challenge.id` in the createTransactionRequest response body. \n |\n |4) `answer` : Defaults to `123`, if running in sandbox mode. In production mode, the value will be sent via the configured SCA method.\n |\n \"\"\".stripMargin",
+ "example_request_body": "challengeAnswerJSON",
+ "success_response_body": "transactionRequestWithChargeJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n BankNotFound,\n UserNoPermissionAccessView,\n TransactionRequestStatusNotInitiated,\n TransactionRequestTypeHasChanged,\n InvalidTransactionRequestChallengeId,\n AllowedAttemptsUsedUp,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "getTransactionRequests": {
+ "partial_function_name_raw": "\"getTransactionRequests\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests\"",
+ "summary": "\"Get Transaction Requests.\"",
+ "description": "\"\"\"Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.\n |\n |The VIEW_ID specified must be 'owner' and the user must have access to this view.\n |\n |Version 2.0.0 now returns charge information.\n |\n |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:\n |\n |* Transaction Request Id\n |* Type\n |* Status (INITIATED, COMPLETED)\n |* Challenge (in order to confirm the request)\n |* From Bank / Account\n |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)\n |* Related Transactions\n |\n |PSD2 Context: PSD2 requires transparency of charges to the customer.\n |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.\n |The customer can proceed with the Transaction by answering the security challenge.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestWithChargeJSONs210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n AccountNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPsd2, apiTagOldStyle)"
+ },
+ "getRoles": {
+ "partial_function_name_raw": "\"getRoles\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/roles\"",
+ "summary": "\"Get Roles\"",
+ "description": "s\"\"\"Returns all available roles\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "availableRolesJSON",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagRole)"
+ },
+ "getEntitlementsByBankAndUser": {
+ "partial_function_name_raw": "\"getEntitlementsByBankAndUser\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/users/USER_ID/entitlements\"",
+ "summary": "\"Get Entitlements for User at Bank\"",
+ "description": "s\"\"\"\n |\n |Get Entitlements specified by BANK_ID and USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementJSONs",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyUserAtOneBank, canGetEntitlementsForAnyUserAtAnyBank))"
+ }
+ },
+ "getConsumer": {
+ "partial_function_name_raw": "\"getConsumer\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Get Consumer\"",
+ "description": "s\"\"\"Get the Consumer specified by CONSUMER_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumerJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidConsumerId,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "getConsumers": {
+ "partial_function_name_raw": "\"getConsumers\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Get Consumers\"",
+ "description": "s\"\"\"Get the all Consumers.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumersJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "enableDisableConsumers": {
+ "partial_function_name_raw": "\"enableDisableConsumers\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Enable or Disable Consumers\"",
+ "description": "s\"\"\"Enable/Disable a Consumer specified by CONSUMER_ID.\n |\n |\"\"\"",
+ "example_request_body": "putEnabledJSON",
+ "success_response_body": "putEnabledJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canEnableConsumers,canDisableConsumers))"
+ }
+ },
+ "addCardsForBank": {
+ "partial_function_name_raw": "\"addCardsForBank\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/cards\"",
+ "summary": "\"Create Card\"",
+ "description": "s\"\"\"Create Card at bank specified by BANK_ID .\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postPhysicalCardJSON",
+ "success_response_body": "physicalCardJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n AllowedValuesAre,\n UnknownError\n )",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCardsForBank))"
+ }
+ },
+ "getUsers": {
+ "partial_function_name_raw": "\"getUsers\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Get all Users\"",
+ "description": "s\"\"\"Get all users\n |\n |Login is required.\n |CanGetAnyUser entitlement is required,\n |\n |${urlParametersDocument(false, false)}\n |* locked_status (if null ignore)\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "createTransactionType": {
+ "partial_function_name_raw": "\"createTransactionType\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/transaction-types\"",
+ "summary": "\"Create Transaction Type at bank\"",
+ "description": "s\"\"\"Create Transaction Types for the bank specified by BANK_ID:\n |\n | * id : Unique transaction type id across the API instance. SHOULD be a UUID. MUST be unique.\n | * bank_id : The bank that supports this TransactionType\n | * short_code : A short code (SHOULD have no-spaces) which MUST be unique across the bank. May be stored with Transactions to link here\n | * summary : A succinct summary\n | * description : A longer description\n | * charge : The charge to the customer for each one of these\n |\n |${userAuthenticationMessage(getTransactionTypesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "transactionTypeJsonV200",
+ "success_response_body": "transactionType",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n InsufficientAuthorisationToCreateTransactionType,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTransactionType))"
+ }
+ },
+ "getAtm": {
+ "partial_function_name_raw": "\"getAtm\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Get Bank ATM\"",
+ "description": "s\"\"\"Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, AtmNotFoundByAtmId, UnknownError)",
+ "tags": "List(apiTagATM, apiTagOldStyle)"
+ },
+ "getBranch": {
+ "partial_function_name_raw": "\"getBranch\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/branches/BRANCH_ID\"",
+ "summary": "\"Get Bank Branch\"",
+ "description": "s\"\"\"Returns information about branches for a single bank specified by BANK_ID and BRANCH_ID including:\n | meta.license.id and eta.license.name fields must not be empty. \n |\n |* Name\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |${userAuthenticationMessage(!getBranchesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "branchJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BranchNotFoundByBranchId,\n UnknownError\n )",
+ "tags": "List(apiTagBranch, apiTagOldStyle)"
+ },
+ "getProduct": {
+ "partial_function_name_raw": "\"getProduct\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Get Bank Product\"",
+ "description": "s\"\"\"Returns information about the financial products offered by a bank specified by BANK_ID and PRODUCT_CODE including:\n |\n |* Name\n |* Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productJsonV210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "getProducts": {
+ "partial_function_name_raw": "\"getProducts\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Get Bank Products\"",
+ "description": "s\"\"\"Returns information about the financial products offered by a bank specified by BANK_ID including:\n |\n |* Name\n |* Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJsonV210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "\"createCustomer\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"Add a customer linked to the user specified by user_id\n |The Customer resource stores the customer number, legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |\n |${userAuthenticationMessage(true)}\n |\n |$createCustomeEntitlementsRequiredText\n |\"\"\"",
+ "example_request_body": "postCustomerJsonV210",
+ "success_response_body": "customerJsonV210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer,canCreateUserCustomerLink,canCreateCustomerAtAnyBank,canCreateUserCustomerLinkAtAnyBank))"
+ }
+ },
+ "getCustomersForUser": {
+ "partial_function_name_raw": "\"getCustomersForUser\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/customers\"",
+ "summary": "\"Get Customers for Current User\"",
+ "description": "\"\"\"Gets all Customers that are linked to a User.\n |\n |Authentication via OAuth is required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJsonV210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser, apiTagOldStyle)"
+ },
+ "getCustomersForCurrentUserAtBank": {
+ "partial_function_name_raw": "\"getCustomersForCurrentUserAtBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Get Customers for current User at Bank\"",
+ "description": "s\"\"\"Returns a list of Customers at the Bank that are linked to the currently authenticated User.\n |\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONs",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserCustomerLinksNotFoundForUser,\n UserCustomerLinksNotFoundForUser,\n CustomerNotFoundByCustomerId,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)"
+ },
+ "updateBranch": {
+ "partial_function_name_raw": "\"updateBranch\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/branches/BRANCH_ID\"",
+ "summary": "\"Update Branch\"",
+ "description": "s\"\"\"Update an existing branch for a bank account (Authenticated access).\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "branchJsonPut",
+ "success_response_body": "branchJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagBranch)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBranch))"
+ }
+ },
+ "createBranch": {
+ "partial_function_name_raw": "\"createBranch\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/branches\"",
+ "summary": "\"Create Branch\"",
+ "description": "s\"\"\"Create branch for the bank (Authenticated access).\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "branchJsonPost",
+ "success_response_body": "branchJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n InsufficientAuthorisationToCreateBranch,\n UnknownError\n )",
+ "tags": "List(apiTagBranch, apiTagOpenData)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBranch, canCreateBranchAtAnyBank))"
+ }
+ },
+ "updateConsumerRedirectUrl": {
+ "partial_function_name_raw": "\"updateConsumerRedirectUrl\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/redirect_url\"",
+ "summary": "\"Update Consumer RedirectUrl\"",
+ "description": "s\"\"\"Update an existing redirectUrl for a Consumer specified by CONSUMER_ID.\n |\n | CONSUMER_ID can be obtained after you register the application. \n | \n | Or use the endpoint 'Get Consumers' to get it \n | \n \"\"\".stripMargin",
+ "example_request_body": "consumerRedirectUrlJSON",
+ "success_response_body": "consumerJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsumerRedirectUrl))"
+ }
+ },
+ "getMetrics": {
+ "partial_function_name_raw": "\"getMetrics\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics\"",
+ "summary": "\"Get Metrics\"",
+ "description": "s\"\"\"Get the all metrics\n |\n |require CanReadMetrics role\n |\n |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics\n |\n |Should be able to filter on the following metrics fields\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString\n |\n |3 limit (for pagination: defaults to 50) eg:limit=200\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |5 sort_by (defaults to date field) eg: sort_by=date\n | possible values:\n | \"url\",\n | \"date\",\n | \"username\" (or \"user_name\" for backward compatibility),\n | \"app_name\",\n | \"developer_email\",\n | \"implemented_by_partial_function\",\n | \"implemented_in_version\",\n | \"consumer_id\",\n | \"verb\"\n |\n |6 direction (defaults to date desc) eg: direction=desc\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78\n |\n |Other filters:\n |\n |7 consumer_id (if null ignore)\n |\n |8 user_id (if null ignore)\n |\n |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |10 url (if null ignore), note: can not contain '&'.\n |\n |11 app_name (if null ignore)\n |\n |12 implemented_by_partial_function (if null ignore),\n |\n |13 implemented_in_version (if null ignore)\n |\n |14 verb (if null ignore)\n |\n |15 correlation_id (if null ignore)\n |\n |16 duration (if null ignore) non digit chars will be silently omitted\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "metricsJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v2_2_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v2_2_0.json
new file mode 100644
index 0000000000..86cb4ff156
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v2_2_0.json
@@ -0,0 +1,234 @@
+{
+ "schema_version": 1,
+ "version": "v2_2_0",
+ "source_file": "obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 18,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getViewsForBankAccount": {
+ "partial_function_name_raw": "\"getViewsForBankAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Get Views for Account\"",
+ "description": "s\"\"\"#Views\n |\n |\n |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. \n |Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.\n |\n |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.\n |\n |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.\n |\n |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.\n |\n |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.\n |\n |**Metadata:**\n |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.\n |\n |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).\n |\n |# All\n |*Optional*\n |\n |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJSONV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "createViewForBankAccount": {
+ "partial_function_name_raw": "\"createViewForBankAccount\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Create View\"",
+ "description": "s\"\"\"#Create a view on bank account\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n | The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | You should use a leading _ (underscore) for the view name because other view names may become reserved by OBP internally\n | \"\"\"",
+ "example_request_body": "createViewJsonV121",
+ "success_response_body": "viewJSONV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagView, apiTagOldStyle)"
+ },
+ "updateViewForBankAccount": {
+ "partial_function_name_raw": "\"updateViewForBankAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Update View\"",
+ "description": "s\"\"\"Update an existing view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateViewJsonV121",
+ "success_response_body": "viewJSONV220",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagView, apiTagOldStyle)"
+ },
+ "getCurrentFxRate": {
+ "partial_function_name_raw": "\"getCurrentFxRate\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/fx/FROM_CURRENCY_CODE/TO_CURRENCY_CODE\"",
+ "summary": "\"Get Current FxRate\"",
+ "description": "\"\"\"Get the latest FX rate specified by BANK_ID, FROM_CURRENCY_CODE and TO_CURRENCY_CODE\n |\n |OBP may try different sources of FX rate information depending on the Connector in operation.\n |\n |For example we want to convert EUR => USD:\n |\n |OBP will:\n |1st try - Connector (database, core banking system or external FX service)\n |2nd try part 1 - fallbackexchangerates/eur.json\n |2nd try part 2 - fallbackexchangerates/usd.json (the inverse rate is used)\n |3rd try - Hardcoded map of FX rates.\n |\n |\n |\n |**Public Access:** This endpoint can be made publicly accessible (no authentication required) by setting the property `apiOptions.getCurrentFxRateIsPublic=true` in the props file.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "fXRateJSON",
+ "error_response_bodies": "List(InvalidISOCurrencyCode,AuthenticatedUserIsRequired,FXCurrencyCodeCombinationsNotSupported, UnknownError)",
+ "tags": "List(apiTagFx)"
+ },
+ "getExplicitCounterpartiesForAccount": {
+ "partial_function_name_raw": "\"getExplicitCounterpartiesForAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Get Counterparties (Explicit)\"",
+ "description": "s\"\"\"This endpoints gets the explicit Counterparties on an Account / View.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary.getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartiesJsonV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n NoViewPermission,\n UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagPSD2PIS, apiTagAccount, apiTagPsd2)"
+ },
+ "getExplicitCounterpartyById": {
+ "partial_function_name_raw": "\"getExplicitCounterpartyById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID\"",
+ "summary": "\"Get Counterparty by Counterparty Id (Explicit)\"",
+ "description": "s\"\"\"Information returned about the Counterparty specified by COUNTERPARTY_ID:\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyWithMetadataJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, UnknownError)",
+ "tags": "List(apiTagCounterparty, apiTagPSD2PIS, apiTagCounterpartyMetaData, apiTagPsd2)"
+ },
+ "getMessageDocs": {
+ "partial_function_name_raw": "\"getMessageDocs\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/message-docs/CONNECTOR\"",
+ "summary": "\"Get Message Docs\"",
+ "description": "\"\"\"These message docs provide example messages sent by OBP to the (RabbitMq) message queue for processing by the Core Banking / Payment system Adapter - together with an example expected response and possible error codes.\n | Integrators can use these messages to build Adapters that provide core banking services to OBP.\n |\n | Note: API Explorer provides a Message Docs page where these messages are displayed.\n | \n | `CONNECTOR`: rest_vMar2019, stored_procedure_vDec2019 ...\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "messageDocsJson",
+ "error_response_bodies": "List(InvalidConnector, UnknownError)",
+ "tags": "List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)"
+ },
+ "createBank": {
+ "partial_function_name_raw": "\"createBank\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Create Bank\"",
+ "description": "s\"\"\"Create a new bank (Authenticated access).\n |${userAuthenticationMessage(true) }\n |\"\"\"",
+ "example_request_body": "bankJSONV220",
+ "success_response_body": "bankJSONV220",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n InsufficientAuthorisationToCreateBank,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBank))"
+ }
+ },
+ "createBranch": {
+ "partial_function_name_raw": "\"createBranch\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/branches\"",
+ "summary": "\"Create Branch\"",
+ "description": "s\"\"\"Create Branch for the Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "branchJsonV220",
+ "success_response_body": "branchJsonV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InsufficientAuthorisationToCreateBranch,\n UnknownError\n )",
+ "tags": "List(apiTagBranch, apiTagOpenData)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBranch,canCreateBranchAtAnyBank))"
+ }
+ },
+ "createAtm": {
+ "partial_function_name_raw": "\"createAtm\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Create ATM\"",
+ "description": "s\"\"\"Create ATM for the Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "atmJsonV220",
+ "success_response_body": "atmJsonV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAtm,canCreateAtmAtAnyBank))"
+ }
+ },
+ "createProduct": {
+ "partial_function_name_raw": "\"createProduct\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Create Product\"",
+ "description": "s\"\"\"Create or Update Product for the Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "productJsonV220",
+ "success_response_body": "productJsonV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProduct, canCreateProductAtAnyBank))"
+ }
+ },
+ "createFx": {
+ "partial_function_name_raw": "\"createFx\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/fx\"",
+ "summary": "\"Create Fx\"",
+ "description": "s\"\"\"Create or Update Fx for the Bank.\n |\n |Example:\n |\n |“from_currency_code”:“EUR”,\n |“to_currency_code”:“USD”,\n |“conversion_value”: 1.136305,\n |“inverse_conversion_value”: 1 / 1.136305 = 0.8800454103431737,\n |\n | Thus 1 Euro = 1.136305 US Dollar\n | and\n | 1 US Dollar = 0.8800 Euro\n |\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "fxJsonV220",
+ "success_response_body": "fxJsonV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagFx)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateFxRate, canCreateFxRateAtAnyBank))"
+ }
+ },
+ "createAccount": {
+ "partial_function_name_raw": "\"createAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Create Account\"",
+ "description": "\"\"\"Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.\n |\n |\n |The User can create an Account for themself or an Account for another User if they have CanCreateAccount role.\n |\n |If USER_ID is not specified the account will be owned by the logged in User.\n |\n |The type field should be a product_code from Product.\n |\n |Note: The Amount must be zero.\"\"\".stripMargin",
+ "example_request_body": "createAccountJSONV220",
+ "success_response_body": "createAccountJSONV220",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankNotFound,\n AuthenticatedUserIsRequired,\n InvalidUserId,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n UserNotFoundById,\n UserHasMissingRoles,\n InvalidAccountBalanceAmount,\n InvalidAccountInitialBalance,\n InitialBalanceMustBeZero,\n InvalidAccountBalanceCurrency,\n AccountIdAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagAccount,apiTagOnboarding)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccount))"
+ }
+ },
+ "config": {
+ "partial_function_name_raw": "\"config\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/config\"",
+ "summary": "\"Get API Configuration\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API Config\n |* Akka ports\n |* Elastic search ports\n |* Cached function \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "configurationJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "apiTagApi :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConfig))"
+ }
+ },
+ "getConnectorMetrics": {
+ "partial_function_name_raw": "\"getConnectorMetrics\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/connector/metrics\"",
+ "summary": "\"Get Connector Metrics\"",
+ "description": "s\"\"\"Get the all metrics\n |\n |require CanGetConnectorMetrics role\n |\n |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/connector/metrics\n |\n |Should be able to filter on the following metrics fields\n |\n |eg: /management/connector/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString\n |\n |3 limit (for pagination: defaults to 1000) eg:limit=2000\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |eg: /management/connector/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=100&offset=300\n |\n |Other filters:\n |\n |5 connector_name (if null ignore)\n |\n |6 function_name (if null ignore)\n |\n |7 correlation_id (if null ignore)\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "connectorMetricsJson",
+ "error_response_bodies": "List(\n InvalidDateFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConnectorMetrics))"
+ }
+ },
+ "createConsumer": {
+ "partial_function_name_raw": "\"createConsumer\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Post a Consumer\"",
+ "description": "s\"\"\"Create a Consumer (Authenticated access).\n |\n |\"\"\"",
+ "example_request_body": "ConsumerPostJSON(\n \"Test\",\n \"Test\",\n \"Description\",\n \"some@email.com\",\n \"redirecturl\",\n \"createdby\",\n true,\n new Date(),\n \"\"\"-----BEGIN CERTIFICATE-----\n |client_certificate_content\n |-----END CERTIFICATE-----\"\"\".stripMargin\n )",
+ "success_response_body": "ConsumerPostJSON(\n \"Some app name\",\n \"App type\",\n \"Description\",\n \"some.email@example.com\",\n \"Some redirect url\",\n \"Created by UUID\",\n true,\n new Date(),\n \"\"\"-----BEGIN CERTIFICATE-----\n |client_certificate_content\n |-----END CERTIFICATE-----\"\"\".stripMargin\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagOldStyle)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateConsumer))"
+ }
+ },
+ "createCounterparty": {
+ "partial_function_name_raw": "\"createCounterparty\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Create Counterparty (Explicit)\"",
+ "description": "s\"\"\"Create Counterparty (Explicit) for an Account.\n |\n |In OBP, there are two types of Counterparty.\n |\n |* Explicit Counterparties (those here) which we create explicitly and are used in COUNTERPARTY Transaction Requests\n |\n |* Implicit Counterparties (AKA Other Accounts) which are generated automatically from the other sides of Transactions.\n |\n |Explicit Counterparties are created for the account / view\n |They are how the user of the view (e.g. account owner) refers to the other side of the transaction\n |\n |name : the human readable name (e.g. Piano teacher, Miss Nipa)\n |\n |description : the human readable name (e.g. Piano teacher, Miss Nipa)\n |\n |bank_routing_scheme : eg: bankId or bankCode or any other strings\n |\n |bank_routing_address : eg: `gh.29.uk`, must be valid sandbox bankIds\n |\n |account_routing_scheme : eg: AccountId or AccountNumber or any other strings\n |\n |account_routing_address : eg: `1d65db7c-a7b2-4839-af41-95`, must be valid accountIds\n |\n |other_account_secondary_routing_scheme : eg: IBan or any other strings\n |\n |other_account_secondary_routing_address : if it is an IBAN, it should be unique for each counterparty. \n |\n |other_branch_routing_scheme : eg: branchId or any other strings or you can leave it empty, not useful in sandbox mode.\n |\n |other_branch_routing_address : eg: `branch-id-123` or you can leave it empty, not useful in sandbox mode.\n |\n |is_beneficiary : must be set to `true` in order to send payments to this counterparty\n |\n |bespoke: It supports a list of key-value, you can add it to the counterparty.\n |\n |bespoke.key : any info-key you want to add to this counterparty\n | \n |bespoke.value : any info-value you want to add to this counterparty\n |\n |The view specified by VIEW_ID must have the canAddCounterparty permission\n |\n |A minimal example for TransactionRequestType == COUNTERPARTY\n | {\n | \"name\": \"Tesobe1\",\n | \"description\": \"Good Company\",\n | \"other_bank_routing_scheme\": \"OBP\",\n | \"other_bank_routing_address\": \"gh.29.uk\",\n | \"other_account_routing_scheme\": \"OBP\",\n | \"other_account_routing_address\": \"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | \"is_beneficiary\": true,\n | \"other_account_secondary_routing_scheme\": \"\",\n | \"other_account_secondary_routing_address\": \"\",\n | \"other_branch_routing_scheme\": \"\",\n | \"other_branch_routing_address\": \"\",\n | \"bespoke\": []\n |}\n |\n | \n |A minimal example for TransactionRequestType == SEPA\n | \n | {\n | \"name\": \"Tesobe2\",\n | \"description\": \"Good Company\",\n | \"other_bank_routing_scheme\": \"OBP\",\n | \"other_bank_routing_address\": \"gh.29.uk\",\n | \"other_account_routing_scheme\": \"OBP\",\n | \"other_account_routing_address\": \"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | \"other_account_secondary_routing_scheme\": \"IBAN\",\n | \"other_account_secondary_routing_address\": \"DE89 3704 0044 0532 0130 00\",\n | \"is_beneficiary\": true,\n | \"other_branch_routing_scheme\": \"\",\n | \"other_branch_routing_address\": \"\",\n | \"bespoke\": []\n |}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postCounterpartyJSON",
+ "success_response_body": "counterpartyWithMetadataJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n BankNotFound,\n AccountNotFound,\n InvalidJsonFormat,\n ViewNotFound,\n CounterpartyAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v3_0_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v3_0_0.json
new file mode 100644
index 0000000000..946dff92e5
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v3_0_0.json
@@ -0,0 +1,586 @@
+{
+ "schema_version": 1,
+ "version": "v3_0_0",
+ "source_file": "obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 47,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getViewsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getViewsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Get Views for Account\"",
+ "description": "s\"\"\"#Views\n |\n |\n |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.\n |\n |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.\n |\n |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.\n |\n |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.\n |\n |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.\n |\n |**Metadata:**\n |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.\n |\n |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).\n |\n |# All\n |*Optional*\n |\n |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "createViewForBankAccount": {
+ "partial_function_name_raw": "nameOf(createViewForBankAccount)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Create Custom View\"",
+ "description": "s\"\"\"Create a custom view on bank account\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n | The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n | You MUST use a leading _ (underscore) in the view name because other view names are reserved for OBP [system views](/index#group-View-System).\n | \"\"\"",
+ "example_request_body": "SwaggerDefinitionsJSON.createViewJsonV300",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "getPermissionForUserForBankAccount": {
+ "partial_function_name_raw": "nameOf(getPermissionForUserForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/permissions/PROVIDER/PROVIDER_ID\"",
+ "summary": "\"Get Account access for User\"",
+ "description": "s\"\"\"Returns the list of the views at BANK_ID for account ACCOUNT_ID that a user identified by PROVIDER_ID at their provider PROVIDER has access to.\n |All url parameters must be [%-encoded](http://en.wikipedia.org/wiki/Percent-encoding), which is often especially relevant for USER_ID and PROVIDER.\n |\n |${userAuthenticationMessage(true)}\n |\n |The user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,BankNotFound, AccountNotFound,UnknownError)",
+ "tags": "List(apiTagView, apiTagAccount, apiTagUser)"
+ },
+ "updateViewForBankAccount": {
+ "partial_function_name_raw": "nameOf(updateViewForBankAccount)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Update Custom View\"",
+ "description": "s\"\"\"Update an existing custom view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateViewJsonV300",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "getPrivateAccountById": {
+ "partial_function_name_raw": "nameOf(getPrivateAccountById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Account by Id (Full)\"",
+ "description": "\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |* Available views (sorted by short_name)\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountJsonV300",
+ "error_response_bodies": "List(BankNotFound,AccountNotFound,ViewNotFound, UserNoPermissionAccessView, UnknownError)",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "getPublicAccountById": {
+ "partial_function_name_raw": "nameOf(getPublicAccountById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/public/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Public Account by Id\"",
+ "description": "s\"\"\"\n |Returns information about an account that has a public view.\n |\n |The account is specified by ACCOUNT_ID. The information is moderated by the view specified by VIEW_ID.\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* Routing\n |\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountJsonV300",
+ "error_response_bodies": "List(BankNotFound,AccountNotFound,ViewNotFound, UnknownError)",
+ "tags": "apiTagAccountPublic :: apiTagAccount :: Nil"
+ },
+ "getCoreAccountById": {
+ "partial_function_name_raw": "nameOf(getCoreAccountById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/account\"",
+ "summary": "\"Get Account by Id (Core)\"",
+ "description": "s\"\"\"Information returned about the account specified by ACCOUNT_ID:\n |\n |* Number - The human readable account number given by the bank that identifies the account.\n |* Label - A label given by the owner of the account\n |* Owners - Users that own this account\n |* Type - The type of account\n |* Balance - Currency and Value\n |* Account Routings - A list that might include IBAN or national account identifiers\n |* Account Rules - A list that might include Overdraft and other bank specific rules\n |\n |This call returns the owner view and requires access to that view.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "newModeratedCoreAccountJsonV300",
+ "error_response_bodies": "List(BankAccountNotFound,UnknownError)",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "corePrivateAccountsAllBanks": {
+ "partial_function_name_raw": "nameOf(corePrivateAccountsAllBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/accounts\"",
+ "summary": "\"Get Accounts at all Banks (private)\"",
+ "description": "s\"\"\"Returns the list of accounts containing private views for the user.\n |Each account lists the views available to the user.\n |\n |${accountTypeFilterText(\"/my/accounts\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPSD2AIS, apiTagPrivateData, apiTagPsd2)"
+ },
+ "getFirehoseAccountsAtOneBank": {
+ "partial_function_name_raw": "nameOf(getFirehoseAccountsAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/firehose/accounts/views/VIEW_ID\"",
+ "summary": "\"Get Firehose Accounts at Bank\"",
+ "description": "s\"\"\"\n |Get all Accounts at a Bank.\n |\n |This endpoint allows bulk access to all accounts at the specified bank.\n |\n |Requires the CanUseFirehoseAtAnyBank Role or CanUseAccountFirehose Role\n |\n |Returns all accounts at the bank. The VIEW_ID parameter determines what account data fields are visible according to the view's permissions.\n |\n |The view specified must have is_firehose = true\n |\n |For VIEW_ID try 'owner' or 'firehose'\n |\n |Optional request parameters for filtering by account attributes:\n |URL params example:\n | /banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1\n |\n |To invalidate browser cache, add timestamp query parameter as follows (the parameter name must be `_timestamp_`):\n |URL params example:\n | `/banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1&_timestamp_=1596762180358`\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,AccountFirehoseNotAllowedOnThisInstance,UnknownError)",
+ "tags": "List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData)",
+ "extra_named_args": {
+ "roles": "Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))"
+ }
+ },
+ "getFirehoseTransactionsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getFirehoseTransactionsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/firehose/accounts/ACCOUNT_ID/views/VIEW_ID/transactions\"",
+ "summary": "\"Get Firehose Transactions for Account\"",
+ "description": "s\"\"\"\n |Get Transactions for an Account that has a firehose View.\n |\n |Allows bulk access to an account's transactions.\n |User must have the CanUseFirehoseAtAnyBank Role\n |\n |To find ACCOUNT_IDs, use the getFirehoseAccountsAtOneBank call.\n |\n |For VIEW_ID try 'owner'\n |\n |${urlParametersDocument(true, true)}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, AccountFirehoseNotAllowedOnThisInstance, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagTransaction, apiTagAccountFirehose, apiTagTransactionFirehose, apiTagFirehoseData)",
+ "extra_named_args": {
+ "roles": "Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))"
+ }
+ },
+ "getCoreTransactionsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getCoreTransactionsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/transactions\"",
+ "summary": "\"Get Transactions for Account (Core)\"",
+ "description": "s\"\"\"Returns transactions list (Core info) of the account specified by ACCOUNT_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreTransactionsJsonV300",
+ "error_response_bodies": "List(\n FilterSortDirectionError,\n FilterOffersetError,\n FilterLimitError ,\n FilterDateFormatError,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagPSD2AIS, apiTagAccount, apiTagPsd2)"
+ },
+ "getTransactionsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getTransactionsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions\"",
+ "summary": "\"Get Transactions for Account (Full)\"",
+ "description": "s\"\"\"Returns transactions list of the account specified by ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).\n |\n |${userAuthenticationMessage(false)}\n |\n |Authentication is required if the view is not public.\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionsJsonV300",
+ "error_response_bodies": "List(\n FilterSortDirectionError,\n FilterOffersetError,\n FilterLimitError ,\n FilterDateFormatError,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagAccount)"
+ },
+ "dataWarehouseSearch": {
+ "partial_function_name_raw": "nameOf(dataWarehouseSearch)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/search/warehouse/INDEX\"",
+ "summary": "\"Data Warehouse Search\"",
+ "description": "s\"\"\"\n |Search the data warehouse and get row level results.\n |\n |${userAuthenticationMessage(true)}\n |\n |CanSearchWarehouse entitlement is required. You can request the Role below.\n |\n |Elastic (search) is used in the background. See links below for syntax.\n |\n |Examples of usage:\n |\n |\n |POST /search/warehouse/THE_INDEX_YOU_WANT_TO_USE\n |\n |POST /search/warehouse/INDEX1,INDEX2\n |\n |POST /search/warehouse/ALL\n |\n |{ Any valid elasticsearch query DSL in the body }\n |\n |\n |[Elasticsearch query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html)\n |\n |[Elastic simple query](https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-request-body.html)\n |\n |[Elastic aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations.html)\n |\n |\n \"\"\"",
+ "example_request_body": "elasticSearchJsonV300",
+ "success_response_body": "emptyElasticSearch",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagSearchWarehouse)",
+ "extra_named_args": {
+ "roles": "Some(List(canSearchWarehouse))"
+ }
+ },
+ "dataWarehouseStatistics": {
+ "partial_function_name_raw": "nameOf(dataWarehouseStatistics)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/search/warehouse/statistics/INDEX/FIELD\"",
+ "summary": "\"Data Warehouse Statistics\"",
+ "description": "s\"\"\"\n |Search the data warehouse and get statistical aggregations over a warehouse field\n |\n |Does a stats aggregation over some numeric field:\n |\n |https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-stats-aggregation.html\n |\n |${userAuthenticationMessage(true)}\n |\n |CanSearchWarehouseStats Role is required. You can request this below.\n |\n |Elastic (search) is used in the background. See links below for syntax.\n |\n |Examples of usage:\n |\n |POST /search/warehouse/statistics/INDEX/FIELD\n |\n |POST /search/warehouse/statistics/ALL/FIELD\n |\n |{ Any valid elasticsearch query DSL in the body }\n |\n |\n |[Elasticsearch query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html)\n |\n |[Elastic simple query](https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-request-body.html)\n |\n |[Elastic aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations.html)\n |\n |\n \"\"\"",
+ "example_request_body": "elasticSearchJsonV300",
+ "success_response_body": "emptyElasticSearch",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagSearchWarehouse)",
+ "extra_named_args": {
+ "roles": "Some(List(canSearchWarehouseStatistics))"
+ }
+ },
+ "getUser": {
+ "partial_function_name_raw": "nameOf(getUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/email/USER_EMAIL/terminator\"",
+ "summary": "\"Get Users by Email Address\"",
+ "description": "s\"\"\"Get users by email address\n |\n |${userAuthenticationMessage(true)}\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundByEmail, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUserByUserId": {
+ "partial_function_name_raw": "nameOf(getUserByUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/user_id/USER_ID\"",
+ "summary": "\"Get User by USER_ID\"",
+ "description": "s\"\"\"Get user by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundById, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUserByUsername": {
+ "partial_function_name_raw": "nameOf(getUserByUsername)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/username/USERNAME\"",
+ "summary": "\"Get User by USERNAME\"",
+ "description": "s\"\"\"Get user by USERNAME\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getAdapterInfoForBank": {
+ "partial_function_name_raw": "nameOf(getAdapterInfoForBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/adapter\"",
+ "summary": "\"Get Adapter Info for a bank\"",
+ "description": "s\"\"\"Get basic information about the Adapter listening on behalf of this bank.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "adapterInfoJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAdapterInfoAtOneBank))"
+ }
+ },
+ "createBranch": {
+ "partial_function_name_raw": "nameOf(createBranch)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/branches\"",
+ "summary": "\"Create Branch\"",
+ "description": "s\"\"\"Create Branch for the Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "branchJsonV300",
+ "success_response_body": "branchJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InsufficientAuthorisationToCreateBranch,\n UnknownError\n )",
+ "tags": "List(apiTagBranch)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBranch, canCreateBranchAtAnyBank))"
+ }
+ },
+ "updateBranch": {
+ "partial_function_name_raw": "nameOf(updateBranch)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/branches/BRANCH_ID\"",
+ "summary": "\"Update Branch\"",
+ "description": "s\"\"\"Update an existing branch for a bank account (Authenticated access).\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "postBranchJsonV300",
+ "success_response_body": "branchJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InsufficientAuthorisationToCreateBranch,\n UnknownError\n )",
+ "tags": "List(apiTagBranch)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBranch))"
+ }
+ },
+ "createAtm": {
+ "partial_function_name_raw": "nameOf(createAtm)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Create ATM\"",
+ "description": "s\"\"\"Create ATM for the Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "atmJsonV300",
+ "success_response_body": "atmJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAtm,canCreateAtmAtAnyBank))"
+ }
+ },
+ "getBranch": {
+ "partial_function_name_raw": "nameOf(getBranch)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/branches/BRANCH_ID\"",
+ "summary": "\"Get Branch\"",
+ "description": "s\"\"\"Returns information about a single Branch specified by BANK_ID and BRANCH_ID including:\n |\n |* Name\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under.\n |\n |${userAuthenticationMessage(!getBranchesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "branchJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BranchNotFoundByBranchId,\n UnknownError\n )",
+ "tags": "List(apiTagBranch, apiTagBank)"
+ },
+ "getBranches": {
+ "partial_function_name_raw": "nameOf(getBranches)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/branches\"",
+ "summary": "\"Get Branches for a Bank\"",
+ "description": "s\"\"\"Returns information about branches for a single bank specified by BANK_ID including:\n |\n |* Name\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |* Structured opening hours\n |* Accessible flag\n |* Branch Type\n |* More Info\n |\n |Pagination:\n |\n |By default, 50 records are returned.\n |\n |You can use the url query parameters *limit* and *offset* for pagination\n |You can also use the follow url query parameters:\n |\n | - city - string, find Branches those in this city, optional\n |\n |\n | - withinMetersOf - number, find Branches within given meters distance, optional\n | - nearLatitude - number, a position of latitude value, cooperate with withMetersOf do query filter, optional\n | - nearLongitude - number, a position of longitude value, cooperate with withMetersOf do query filter, optional\n |\n |note: withinMetersOf, nearLatitude and nearLongitude either all empty or all have value.\n |\n |${userAuthenticationMessage(!getBranchesIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "branchesJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BranchesNotFoundLicense,\n UnknownError)",
+ "tags": "List(apiTagBranch, apiTagBank)"
+ },
+ "getAtm": {
+ "partial_function_name_raw": "nameOf(getAtm)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Get Bank ATM\"",
+ "description": "s\"\"\"Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, AtmNotFoundByAtmId, UnknownError)",
+ "tags": "List(apiTagATM)"
+ },
+ "getAtms": {
+ "partial_function_name_raw": "nameOf(getAtms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Get Bank ATMS\"",
+ "description": "s\"\"\"Returns information about ATMs for a single bank specified by BANK_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |Pagination:\n |\n |By default, 100 records are returned.\n |\n |You can use the url query parameters *limit* and *offset* for pagination\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n \"No ATMs available. License may not be set.\",\n UnknownError)",
+ "tags": "List(apiTagATM)"
+ },
+ "getUsers": {
+ "partial_function_name_raw": "nameOf(getUsers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Get all Users\"",
+ "description": "s\"\"\"Get all users\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required,\n |\n |${urlParametersDocument(false, false)}\n |* locked_status (if null ignore)\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV200",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getCustomersForUser": {
+ "partial_function_name_raw": "nameOf(getCustomersForUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/customers\"",
+ "summary": "\"Get Customers for Current User\"",
+ "description": "s\"\"\"Gets all Customers that are linked to a User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersWithAttributesJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)"
+ },
+ "getCurrentUser": {
+ "partial_function_name_raw": "nameOf(getCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current\"",
+ "summary": "\"Get User (Current)\"",
+ "description": "s\"\"\"Get the logged in user\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagUser)"
+ },
+ "privateAccountsAtOneBank": {
+ "partial_function_name_raw": "nameOf(privateAccountsAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/private\"",
+ "summary": "\"Get Accounts at Bank (Minimal)\"",
+ "description": "s\"\"\"Returns the minimal list of private accounts at BANK_ID that the user has access to.\n |For each account, the API returns the ID, routing addresses and the views available to the current user.\n |\n |If you want to see more information on the Views, use the Account Detail call.\n |\n |${accountTypeFilterText(\"/banks/BANK_ID/accounts/private\")}\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, UnknownError)",
+ "tags": "List(apiTagAccount,apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getPrivateAccountIdsbyBankId": {
+ "partial_function_name_raw": "nameOf(getPrivateAccountIdsbyBankId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/account_ids/private\"",
+ "summary": "\"Get Accounts at Bank (IDs only)\"",
+ "description": "s\"\"\"Returns only the list of accounts ids at BANK_ID that the user has access to.\n |\n |Each account must have at least one private View.\n |\n |For each account the API returns its account ID.\n |\n |If you want to see more information on the Views, use the Account Detail call.\n |\n |${accountTypeFilterText(\"/banks/BANK_ID/accounts/account_ids/private\")}\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountsIdsJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getOtherAccountsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getOtherAccountsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts\"",
+ "summary": "\"Get Other Accounts of one Account\"",
+ "description": "s\"\"\"Returns data about all the other accounts that have shared at least one transaction with the ACCOUNT_ID at BANK_ID.\n |${userAuthenticationMessage(false)}\n |\n |Authentication is required if the view VIEW_ID is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountsJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ },
+ "getOtherAccountByIdForBankAccount": {
+ "partial_function_name_raw": "nameOf(getOtherAccountByIdForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/other_accounts/OTHER_ACCOUNT_ID\"",
+ "summary": "\"Get Other Account by Id\"",
+ "description": "s\"\"\"Returns data about the Other Account that has shared at least one transaction with ACCOUNT_ID at BANK_ID.\n |${userAuthenticationMessage(false)}\n |\n |Authentication is required if the view is not public.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "otherAccountJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n InvalidConnectorResponse,\n UnknownError)",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ },
+ "addEntitlementRequest": {
+ "partial_function_name_raw": "nameOf(addEntitlementRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/entitlement-requests\"",
+ "summary": "\"Create Entitlement Request for current User\"",
+ "description": "s\"\"\"Create Entitlement Request.\n |\n |Any logged in User can use this endpoint to request an Entitlement\n |\n |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views)\n |\n |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. \"bank_id\":\"\"\n |\n |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. \"bank_id\":\"my-bank-id\"\n |\n |\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createEntitlementJSON",
+ "success_response_body": "entitlementRequestJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserNotFoundById,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementIsBankRole,\n EntitlementIsSystemRole,\n EntitlementRequestAlreadyExists,\n EntitlementRequestCannotBeAdded,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)"
+ },
+ "getAllEntitlementRequests": {
+ "partial_function_name_raw": "nameOf(getAllEntitlementRequests)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/entitlement-requests\"",
+ "summary": "\"Get all Entitlement Requests\"",
+ "description": "s\"\"\"\n |Get all Entitlement Requests\n |\n |${urlParametersDocument(true, true)}\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementRequestsJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementRequestsAtOneBank, canGetEntitlementRequestsAtAnyBank))"
+ }
+ },
+ "getEntitlementRequests": {
+ "partial_function_name_raw": "nameOf(getEntitlementRequests)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/entitlement-requests\"",
+ "summary": "\"Get Entitlement Requests for a User\"",
+ "description": "s\"\"\"Get Entitlement Requests for a User.\n |\n |${urlParametersDocument(true, true)}\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementRequestsJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementRequestsAtOneBank, canGetEntitlementRequestsAtAnyBank))"
+ }
+ },
+ "getEntitlementRequestsForCurrentUser": {
+ "partial_function_name_raw": "nameOf(getEntitlementRequestsForCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/entitlement-requests\"",
+ "summary": "\"Get Entitlement Requests for the current User\"",
+ "description": "s\"\"\"Get Entitlement Requests for the current User.\n |\n |${urlParametersDocument(true, true)}\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementRequestsJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "deleteEntitlementRequest": {
+ "partial_function_name_raw": "nameOf(deleteEntitlementRequest)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/entitlement-requests/ENTITLEMENT_REQUEST_ID\"",
+ "summary": "\"Delete Entitlement Request\"",
+ "description": "s\"\"\"Delete the Entitlement Request specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID\n |\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteEntitlementRequestsAtOneBank, canDeleteEntitlementRequestsAtAnyBank))"
+ }
+ },
+ "getEntitlementsForCurrentUser": {
+ "partial_function_name_raw": "nameOf(getEntitlementsForCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/entitlements\"",
+ "summary": "\"Get Entitlements for the current User\"",
+ "description": "s\"\"\"Get Entitlements for the current User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementJSONs",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getApiGlossary": {
+ "partial_function_name_raw": "nameOf(getApiGlossary)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api/glossary\"",
+ "summary": "\"Get Glossary of the API\"",
+ "description": "\"\"\"Get API Glossary\n |\n |Returns the glossary of the API.\n |\n |The glossary content is static and only changes when the API is redeployed.\n |This endpoint supports HTTP caching:\n |\n |* The response includes a **Cache-Control** header (max-age=3600) indicating clients should cache for 1 hour.\n |* The response includes an **ETag** header. Clients can send **If-None-Match** with the ETag value on subsequent requests to receive a **304 Not Modified** if the content has not changed.\n |\n |Clients and agents are encouraged to cache the glossary response locally.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "glossaryItemsJsonV300",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagDocumentation :: Nil"
+ },
+ "getAccountsHeld": {
+ "partial_function_name_raw": "nameOf(getAccountsHeld)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts-held\"",
+ "summary": "\"Get Accounts Held\"",
+ "description": "s\"\"\"Get Accounts held by the current User if even the User has not been assigned the owner View yet.\n |\n |Can be used to onboard the account to the API - since all other account and transaction endpoints require views to be assigned.\n |\n |${accountTypeFilterText(\"/banks/BANK_ID/accounts-held\")}\n |\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsHeldJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPSD2AIS, apiTagView, apiTagPsd2)"
+ },
+ "getAggregateMetrics": {
+ "partial_function_name_raw": "nameOf(getAggregateMetrics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/aggregate-metrics\"",
+ "summary": "\"Get Aggregate Metrics\"",
+ "description": "s\"\"\"Returns aggregate metrics on api usage eg. total count, response time (in ms), etc.\n |\n |Should be able to filter on the following fields\n |\n |eg: /management/aggregate-metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |1 from_date (defaults to the day before the current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to the current date) eg:to_date=$DateWithMsExampleString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore),\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 duration (if null ignore) non digit chars will be silently omitted\n |\n |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "aggregateMetricsJSONV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagAggregateMetrics)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadAggregateMetrics))"
+ }
+ },
+ "addScope": {
+ "partial_function_name_raw": "nameOf(addScope)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumers/CONSUMER_ID/scopes\"",
+ "summary": "\"Create Scope for a Consumer\"",
+ "description": "\"\"\"Create Scope. Grant Role to Consumer.\n |\n |Scopes are used to grant System or Bank level roles to the Consumer (App). (For Account level privileges, see Views)\n |\n |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. \"bank_id\":\"\"\n |\n |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. \"bank_id\":\"my-bank-id\"\n |\n |\"\"\"",
+ "example_request_body": "SwaggerDefinitionsJSON.createScopeJson",
+ "success_response_body": "scopeJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n ConsumerNotFoundById,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementIsBankRole,\n EntitlementIsSystemRole,\n EntitlementAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagScope, apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateScopeAtOneBank, canCreateScopeAtAnyBank))"
+ }
+ },
+ "deleteScope": {
+ "partial_function_name_raw": "nameOf(deleteScope)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/consumers/CONSUMER_ID/scope/SCOPE_ID\"",
+ "summary": "\"Delete Consumer Scope\"",
+ "description": "\"\"\"Delete Consumer Scope specified by SCOPE_ID for an consumer specified by CONSUMER_ID\n |\n |Authentication is required and the user needs to be a Super Admin.\n |Super Admins are listed in the Props file.\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, EntitlementNotFound, UnknownError)",
+ "tags": "List(apiTagScope, apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteScopeAtOneBank, canDeleteScopeAtAnyBank))"
+ }
+ },
+ "getScopes": {
+ "partial_function_name_raw": "nameOf(getScopes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumers/CONSUMER_ID/scopes\"",
+ "summary": "\"Get Scopes for Consumer\"",
+ "description": "s\"\"\"Get all the scopes for an consumer specified by CONSUMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "scopeJsons",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, EntitlementNotFound, UnknownError)",
+ "tags": "List(apiTagScope, apiTagConsumer)"
+ },
+ "getBanks": {
+ "partial_function_name_raw": "nameOf(getBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Get Banks\"",
+ "description": "\"\"\"Get banks on this API instance\n |Returns a list of banks supported on this server:\n |\n |* ID used as parameter in URLs\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "banksJSON",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagBank :: apiTagPSD2AIS:: apiTagPsd2 :: Nil"
+ },
+ "bankById": {
+ "partial_function_name_raw": "nameOf(bankById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID\"",
+ "summary": "\"Get Bank\"",
+ "description": "\"\"\"Get the bank specified by BANK_ID\n |Returns information about a single bank specified by BANK_ID including:\n |\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankJson400",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError, BankNotFound)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v3_1_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v3_1_0.json
new file mode 100644
index 0000000000..975dab43e4
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v3_1_0.json
@@ -0,0 +1,1320 @@
+{
+ "schema_version": 1,
+ "version": "v3_1_0",
+ "source_file": "obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 102,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJSON",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getCheckbookOrders": {
+ "partial_function_name_raw": "nameOf(getCheckbookOrders)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/checkbook/orders\"",
+ "summary": "\"Get Checkbook orders\"",
+ "description": "s\"\"\"${mockedDataText(false)}Get all checkbook orders\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "checkbookOrdersJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BankAccountNotFound,\n InvalidConnectorResponseForGetCheckbookOrdersFuture,\n UnknownError\n )",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "getStatusOfCreditCardOrder": {
+ "partial_function_name_raw": "nameOf(getStatusOfCreditCardOrder)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/credit_cards/orders\"",
+ "summary": "\"Get status of Credit Card order \"",
+ "description": "s\"\"\"${mockedDataText(false)}Get status of Credit Card orders\n |Get all orders\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "creditCardOrderStatusResponseJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BankAccountNotFound,\n InvalidConnectorResponseForGetStatusOfCreditCardOrderFuture,\n UnknownError\n )",
+ "tags": "apiTagCard :: Nil"
+ },
+ "getTopAPIs": {
+ "partial_function_name_raw": "nameOf(getTopAPIs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics/top-apis\"",
+ "summary": "\"Get Top APIs\"",
+ "description": "s\"\"\"Get metrics about the most popular APIs. e.g.: total count, response time (in ms), etc.\n |\n |Should be able to filter on the following fields\n |\n |eg: /management/metrics/top-apis?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString\n |\n |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore),\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 duration (if null ignore) non digit chars will be silently omitted\n |\n |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "topApisJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidFilterParameterFormat,\n GetTopApisError,\n UnknownError\n )",
+ "tags": "apiTagMetric :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "getMetricsTopConsumers": {
+ "partial_function_name_raw": "nameOf(getMetricsTopConsumers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics/top-consumers\"",
+ "summary": "\"Get Top Consumers\"",
+ "description": "s\"\"\"Get metrics about the top consumers of the API usage e.g. total count, consumer_id and app_name.\n |\n |Should be able to filter on the following fields\n |\n |e.g.: /management/metrics/top-consumers?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |&limit=100\n |\n |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString\n |\n |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore),\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 duration (if null ignore) non digit chars will be silently omitted\n |\n |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |16 limit (for pagination: defaults to 50) eg:limit=200\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "topConsumersJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidFilterParameterFormat,\n GetMetricsTopConsumersError,\n UnknownError\n )",
+ "tags": "apiTagMetric :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "getFirehoseCustomers": {
+ "partial_function_name_raw": "nameOf(getFirehoseCustomers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/firehose/customers\"",
+ "summary": "\"Get Firehose Customers\"",
+ "description": "s\"\"\"\n |Get Customers that has a firehose View.\n |\n |Allows bulk access to customers.\n |User must have the CanUseFirehoseAtAnyBank Role\n |\n |${urlParametersDocument(true, true)}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONs",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, CustomerFirehoseNotAllowedOnThisInstance, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagCustomer, apiTagFirehoseData)",
+ "extra_named_args": {
+ "roles": "Some(List(ApiRole.canUseCustomerFirehose, canUseCustomerFirehoseAtAnyBank))"
+ }
+ },
+ "getBadLoginStatus": {
+ "partial_function_name_raw": "nameOf(getBadLoginStatus)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USERNAME/lock-status\"",
+ "summary": "\"Get User Lock Status\"",
+ "description": "s\"\"\"\n |Get User Login Status.\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "badLoginStatusJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadUserLockedStatus))"
+ }
+ },
+ "unlockUser": {
+ "partial_function_name_raw": "nameOf(unlockUser)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/users/USERNAME/lock-status\"",
+ "summary": "\"Unlock the user\"",
+ "description": "s\"\"\"\n |Unlock a User.\n |\n |(Perhaps the user was locked due to multiple failed login attempts)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "badLoginStatusJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canUnlockUser))"
+ }
+ },
+ "callsLimit": {
+ "partial_function_name_raw": "nameOf(callsLimit)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/call-limits\"",
+ "summary": "\"Set Rate Limits (call limits) per Consumer\"",
+ "description": "s\"\"\"\n |Set the API rate limiting (call limits) per Consumer:\n |\n |Rate limits can be set:\n |\n |Per Second\n |Per Minute\n |Per Hour\n |Per Week\n |Per Month\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "callLimitPostJson",
+ "success_response_body": "callLimitPostJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateRateLimits))"
+ }
+ },
+ "getCallsLimit": {
+ "partial_function_name_raw": "nameOf(getCallsLimit)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/call-limits\"",
+ "summary": "\"Get Rate Limits for a Consumer\"",
+ "description": "s\"\"\"\n |Get Rate Limits per Consumer.\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "callLimitJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateRateLimits))"
+ }
+ },
+ "checkFundsAvailable": {
+ "partial_function_name_raw": "nameOf(checkFundsAvailable)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/funds-available\"",
+ "summary": "\"Check Available Funds\"",
+ "description": "\"\"\"Check Available Funds\n |Mandatory URL parameters:\n |\n |* amount=NUMBER\n |* currency=STRING\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "checkFundsAvailableJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BankAccountNotFound,\n InvalidAmount,\n InvalidISOCurrencyCode,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2PIIS :: apiTagPsd2 :: Nil"
+ },
+ "getConsumer": {
+ "partial_function_name_raw": "nameOf(getConsumer)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Get Consumer\"",
+ "description": "s\"\"\"Get the Consumer specified by CONSUMER_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumerJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ConsumerNotFoundByConsumerId,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "getConsumersForCurrentUser": {
+ "partial_function_name_raw": "nameOf(getConsumersForCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/users/current/consumers\"",
+ "summary": "\"Get Consumers (logged in User)\"",
+ "description": "s\"\"\"Get the Consumers for logged in User.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumersJson310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)"
+ },
+ "getConsumers": {
+ "partial_function_name_raw": "nameOf(getConsumers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Get Consumers\"",
+ "description": "s\"\"\"Get the all Consumers.\n |\n |${userAuthenticationMessage(true)}\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumersJson310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "createAccountWebhook": {
+ "partial_function_name_raw": "nameOf(createAccountWebhook)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/account-web-hooks\"",
+ "summary": "\"Create an Account Webhook\"",
+ "description": "s\"\"\"Create an Account Webhook\n |\n |$accountWebHookInfo\n |\"\"\"",
+ "example_request_body": "accountWebhookPostJson",
+ "success_response_body": "accountWebhookJson",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagWebhook :: apiTagBank :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateWebhook))"
+ }
+ },
+ "enableDisableAccountWebhook": {
+ "partial_function_name_raw": "nameOf(enableDisableAccountWebhook)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/account-web-hooks\"",
+ "summary": "\"Enable/Disable an Account Webhook\"",
+ "description": "s\"\"\"Enable/Disable an Account Webhook\n |\n |\n |$accountWebHookInfo\n |\"\"\"",
+ "example_request_body": "accountWebhookPutJson",
+ "success_response_body": "accountWebhookJson",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagWebhook :: apiTagBank :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateWebhook))"
+ }
+ },
+ "getAccountWebhooks": {
+ "partial_function_name_raw": "nameOf(getAccountWebhooks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/account-web-hooks\"",
+ "summary": "\"Get Account Webhooks\"",
+ "description": "s\"\"\"Get Account Webhooks.\n |\n |Possible custom URL parameters for pagination:\n |\n |${urlParametersDocument(false, false)}\n |* account_id=STRING (if null ignore)\n |* user_id=STRING (if null ignore)\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountWebhooksJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "apiTagWebhook :: apiTagBank :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetWebhooks))"
+ }
+ },
+ "config": {
+ "partial_function_name_raw": "nameOf(config)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/config\"",
+ "summary": "\"Get API Configuration\"",
+ "description": "\"\"\"Returns information about:\n |\n |* The default bank_id\n |* Akka configuration\n |* Elastic Search configuration\n |* Cached functions \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "configurationJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "apiTagApi :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConfig))"
+ }
+ },
+ "getAdapterInfo": {
+ "partial_function_name_raw": "nameOf(getAdapterInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/adapter\"",
+ "summary": "\"Get Adapter Info\"",
+ "description": "s\"\"\"Get basic information about the Adapter.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "adapterInfoJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAdapterInfo))"
+ }
+ },
+ "getTransactionByIdForBankAccount": {
+ "partial_function_name_raw": "nameOf(getTransactionByIdForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/transaction\"",
+ "summary": "\"Get Transaction by Id\"",
+ "description": "s\"\"\"Returns one transaction specified by TRANSACTION_ID of the account ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).\n |\n |${userAuthenticationMessage(false)}\n |Authentication is required if the view is not public.\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankAccountNotFound ,ViewNotFound, UserNoPermissionAccessView, UnknownError)",
+ "tags": "List(apiTagTransaction)"
+ },
+ "getTransactionRequests": {
+ "partial_function_name_raw": "nameOf(getTransactionRequests)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests\"",
+ "summary": "\"Get Transaction Requests.\"",
+ "description": "\"\"\"Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.\n |\n |The VIEW_ID specified must be 'owner' and the user must have access to this view.\n |\n |Version 2.0.0 now returns charge information.\n |\n |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:\n |\n |* Transaction Request Id\n |* Type\n |* Status (INITIATED, COMPLETED)\n |* Challenge (in order to confirm the request)\n |* From Bank / Account\n |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)\n |* Related Transactions\n |\n |PSD2 Context: PSD2 requires transparency of charges to the customer.\n |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.\n |The customer can proceed with the Transaction by answering the security challenge.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestWithChargeJSONs210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BankAccountNotFound,\n UserNoPermissionAccessView,\n ViewDoesNotPermitAccess,\n GetTransactionRequestsException,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS)"
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "nameOf(createCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"\n |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |\n |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postCustomerJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateCustomerError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getRateLimitingInfo": {
+ "partial_function_name_raw": "nameOf(getRateLimitingInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/rate-limiting\"",
+ "summary": "\"Get Rate Limiting Info\"",
+ "description": "s\"\"\"Get information about the Rate Limiting setup on this OBP Instance such as:\n |\n |Is rate limiting enabled and active?\n |What backend is used to keep track of the API calls (e.g. REDIS).\n |\n |Note: Rate limiting can be set at the Consumer level and also for anonymous calls.\n |\n |See the consumer rate limits / call limits endpoints.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "rateLimitingInfoV310",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagApi, apiTagRateLimits)"
+ },
+ "getCustomerByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCustomerByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID\"",
+ "summary": "\"Get Customer by CUSTOMER_ID\"",
+ "description": "s\"\"\"Gets the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerWithAttributesJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomerByCustomerNumber": {
+ "partial_function_name_raw": "nameOf(getCustomerByCustomerNumber)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/customer-number\"",
+ "summary": "\"Get Customer by CUSTOMER_NUMBER\"",
+ "description": "s\"\"\"Gets the Customer specified by CUSTOMER_NUMBER.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerNumberJsonV310",
+ "success_response_body": "customerWithAttributesJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "createUserAuthContext": {
+ "partial_function_name_raw": "nameOf(createUserAuthContext)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/auth-context\"",
+ "summary": "\"Create User Auth Context\"",
+ "description": "s\"\"\"Create User Auth Context. These key value pairs will be propagated over connector to adapter. Normally used for mapping OBP user and\n | Bank User/Customer.\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postUserAuthContextJson",
+ "success_response_body": "userAuthContextJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n CreateUserAuthContextError,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateUserAuthContext))"
+ }
+ },
+ "getUserAuthContexts": {
+ "partial_function_name_raw": "nameOf(getUserAuthContexts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/auth-context\"",
+ "summary": "\"Get User Auth Contexts\"",
+ "description": "s\"\"\"Get User Auth Contexts for a User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userAuthContextsJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(canGetUserAuthContext :: Nil)"
+ }
+ },
+ "deleteUserAuthContexts": {
+ "partial_function_name_raw": "nameOf(deleteUserAuthContexts)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/auth-context\"",
+ "summary": "\"Delete User's Auth Contexts\"",
+ "description": "s\"\"\"Delete the Auth Contexts of a User specified by USER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteUserAuthContext))"
+ }
+ },
+ "deleteUserAuthContextById": {
+ "partial_function_name_raw": "nameOf(deleteUserAuthContextById)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/auth-context/USER_AUTH_CONTEXT_ID\"",
+ "summary": "\"Delete User Auth Context\"",
+ "description": "s\"\"\"Delete a User AuthContext of the User specified by USER_AUTH_CONTEXT_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteUserAuthContext))"
+ }
+ },
+ "createTaxResidence": {
+ "partial_function_name_raw": "nameOf(createTaxResidence)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/tax-residence\"",
+ "summary": "\"Create Tax Residence\"",
+ "description": "s\"\"\"Create a Tax Residence for a Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postTaxResidenceJsonV310",
+ "success_response_body": "taxResidenceV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTaxResidence))"
+ }
+ },
+ "getTaxResidence": {
+ "partial_function_name_raw": "nameOf(getTaxResidence)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/tax-residences\"",
+ "summary": "\"Get Tax Residences of Customer\"",
+ "description": "s\"\"\"Get the Tax Residences of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "taxResidencesJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)"
+ },
+ "deleteTaxResidence": {
+ "partial_function_name_raw": "nameOf(deleteTaxResidence)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/tax_residencies/TAX_RESIDENCE_ID\"",
+ "summary": "\"Delete Tax Residence\"",
+ "description": "s\"\"\"Delete a Tax Residence of the Customer specified by TAX_RESIDENCE_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)"
+ },
+ "getAllEntitlements": {
+ "partial_function_name_raw": "nameOf(getAllEntitlements)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/entitlements\"",
+ "summary": "\"Get all Entitlements\"",
+ "description": "s\"\"\"\n |\n |Login is required.\n |\n |Possible filter on the role field:\n |\n |eg: /entitlements?role=${canGetCustomersAtOneBank.toString}\n |\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementJSonsV310",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement)"
+ },
+ "createCustomerAddress": {
+ "partial_function_name_raw": "nameOf(createCustomerAddress)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/address\"",
+ "summary": "\"Create Address\"",
+ "description": "s\"\"\"Create an Address for a Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerAddressJsonV310",
+ "success_response_body": "customerAddressJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomerAddress))"
+ }
+ },
+ "updateCustomerAddress": {
+ "partial_function_name_raw": "nameOf(updateCustomerAddress)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID\"",
+ "summary": "\"Update the Address of a Customer\"",
+ "description": "s\"\"\"Update an Address of the Customer specified by CUSTOMER_ADDRESS_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerAddressJsonV310",
+ "success_response_body": "customerAddressJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)"
+ },
+ "getCustomerAddresses": {
+ "partial_function_name_raw": "nameOf(getCustomerAddresses)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/addresses\"",
+ "summary": "\"Get Customer Addresses\"",
+ "description": "s\"\"\"Get the Addresses of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAddressesJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerAddress))"
+ }
+ },
+ "deleteCustomerAddress": {
+ "partial_function_name_raw": "nameOf(deleteCustomerAddress)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID\"",
+ "summary": "\"Delete Customer Address\"",
+ "description": "s\"\"\"Delete an Address of the Customer specified by CUSTOMER_ADDRESS_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCustomerAddress))"
+ }
+ },
+ "getObpConnectorLoopback": {
+ "partial_function_name_raw": "nameOf(getObpConnectorLoopback)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/connector/loopback\"",
+ "summary": "\"Get Connector Status (Loopback)\"",
+ "description": "s\"\"\"This endpoint makes a call to the Connector to check the backend transport is reachable. (Deprecated)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "obpApiLoopbackJson",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagOAuth, apiTagOIDC)"
+ },
+ "refreshUser": {
+ "partial_function_name_raw": "nameOf(refreshUser)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/refresh\"",
+ "summary": "\"Refresh User\"",
+ "description": "s\"\"\" The endpoint is used for updating the accounts, views, account holders for the user.\n | As to the Json body, you can leave it as Empty.\n | This call will get data from backend, no need to prepare the json body in api side.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "refresUserJson",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canRefreshUser))"
+ }
+ },
+ "createProductAttribute": {
+ "partial_function_name_raw": "nameOf(createProductAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attribute\"",
+ "summary": "\"Create Product Attribute\"",
+ "description": "s\"\"\" Create Product Attribute\n |\n |$productAttributeGeneralInfo\n |\n |Typical product attributes might be:\n |\n |ISIN (for International bonds)\n |VKN (for German bonds)\n |REDCODE (markit short code for credit derivative)\n |LOAN_ID (e.g. used for Anacredit reporting)\n |\n |ISSUE_DATE (When the bond was issued in the market)\n |MATURITY_DATE (End of life time of a product)\n |TRADABLE\n |\n |See [FPML](http://www.fpml.org/) for more examples.\n |\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productAttributeJson",
+ "success_response_body": "productAttributeResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProductAttribute))"
+ }
+ },
+ "getProductAttribute": {
+ "partial_function_name_raw": "nameOf(getProductAttribute)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Get Product Attribute\"",
+ "description": "s\"\"\" Get Product Attribute\n |\n |$productAttributeGeneralInfo\n |\n |Get one product attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productAttributeResponseJson",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetProductAttribute))"
+ }
+ },
+ "updateProductAttribute": {
+ "partial_function_name_raw": "nameOf(updateProductAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Update Product Attribute\"",
+ "description": "s\"\"\" Update Product Attribute.\n |\n\n |$productAttributeGeneralInfo\n |\n |Update one Product Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productAttributeJson",
+ "success_response_body": "productAttributeResponseJson",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateProductAttribute))"
+ }
+ },
+ "deleteProductAttribute": {
+ "partial_function_name_raw": "nameOf(deleteProductAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Product Attribute\"",
+ "description": "s\"\"\" Delete Product Attribute\n |\n |$productAttributeGeneralInfo\n |\n |Delete a Product Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateProductAttribute))"
+ }
+ },
+ "createAccountApplication": {
+ "partial_function_name_raw": "nameOf(createAccountApplication)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/account-applications\"",
+ "summary": "\"Create Account Application\"",
+ "description": "s\"\"\" Create Account Application\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "accountApplicationJson",
+ "success_response_body": "accountApplicationResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccountApplication, apiTagAccount)"
+ },
+ "getAccountApplications": {
+ "partial_function_name_raw": "nameOf(getAccountApplications)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/account-applications\"",
+ "summary": "\"Get Account Applications\"",
+ "description": "s\"\"\"Get the Account Applications.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountApplicationsJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccountApplication, apiTagAccount)"
+ },
+ "getAccountApplication": {
+ "partial_function_name_raw": "nameOf(getAccountApplication)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID\"",
+ "summary": "\"Get Account Application by Id\"",
+ "description": "s\"\"\"Get the Account Application.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountApplicationResponseJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccountApplication, apiTagAccount)"
+ },
+ "updateAccountApplicationStatus": {
+ "partial_function_name_raw": "nameOf(updateAccountApplicationStatus)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID\"",
+ "summary": "\"Update Account Application Status\"",
+ "description": "s\"\"\"Update an Account Application status\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "accountApplicationUpdateStatusJson",
+ "success_response_body": "accountApplicationResponseJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccountApplication, apiTagAccount)"
+ },
+ "createProduct": {
+ "partial_function_name_raw": "\"createProduct\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Create Product\"",
+ "description": "s\"\"\"Create or Update Product for the Bank.\n |\n |\n |Typical Super Family values / Asset classes are:\n |\n |Debt\n |Equity\n |FX\n |Commodity\n |Derivative\n |\n |$productHiearchyAndCollectionNote\n |\n |\n |${userAuthenticationMessage(true) }\n |\n |\n |\"\"\"",
+ "example_request_body": "postPutProductJsonV310",
+ "success_response_body": "productJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProduct, canCreateProductAtAnyBank))"
+ }
+ },
+ "getProduct": {
+ "partial_function_name_raw": "\"getProduct\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Get Bank Product\"",
+ "description": "s\"\"\"Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including:\n |\n |* Name\n |* Code\n |* Parent Product Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "getProductTree": {
+ "partial_function_name_raw": "nameOf(getProductTree)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/product-tree/PRODUCT_CODE\"",
+ "summary": "\"Get Product Tree\"",
+ "description": "s\"\"\"Returns information about a particular financial product specified by BANK_ID and PRODUCT_CODE\n |and it's parent product(s) recursively as specified by parent_product_code.\n |\n |Each product includes the following information.\n |\n |* Name\n |* Code\n |* Parent Product Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License: The licence under which this product data is released. Licence can be an Open Data licence such as Open Data Commons Public Domain Dedication and License (PDDL) or Copyright etc.\n |\n |\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "childProductTreeJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "getProducts": {
+ "partial_function_name_raw": "\"getProducts\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Get Products\"",
+ "description": "s\"\"\"Returns information about the financial products offered by a bank specified by BANK_ID including:\n |\n |* Name\n |* Code\n |* Parent Product Code\n |* Category\n |* Family\n |* Super Family\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |\n |Can filter with attributes name and values.\n |URL params example: /banks/some-bank-id/products?&limit=50&offset=1\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "createAccountAttribute": {
+ "partial_function_name_raw": "nameOf(createAccountAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attribute\"",
+ "summary": "\"Create Account Attribute\"",
+ "description": "s\"\"\" Create Account Attribute\n |\n |$accountAttributeGeneralInfo\n |\n |Typical account attributes might be:\n |\n |ISIN (for International bonds)\n |VKN (for German bonds)\n |REDCODE (markit short code for credit derivative)\n |LOAN_ID (e.g. used for Anacredit reporting)\n |\n |ISSUE_DATE (When the bond was issued in the market)\n |MATURITY_DATE (End of life time of a product)\n |TRADABLE\n |\n |See [FPML](http://www.fpml.org/) for more examples.\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "accountAttributeJson",
+ "success_response_body": "accountAttributeResponseJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccountAttributeAtOneBank))"
+ }
+ },
+ "updateAccountAttribute": {
+ "partial_function_name_raw": "nameOf(updateAccountAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attributes/ACCOUNT_ATTRIBUTE_ID\"",
+ "summary": "\"Update Account Attribute\"",
+ "description": "s\"\"\" Update Account Attribute\n |\n |$accountAttributeGeneralInfo\n |\n |Typical account attributes might be:\n |\n |ISIN (for International bonds)\n |VKN (for German bonds)\n |REDCODE (markit short code for credit derivative)\n |LOAN_ID (e.g. used for Anacredit reporting)\n |\n |ISSUE_DATE (When the bond was issued in the market)\n |MATURITY_DATE (End of life time of a product)\n |TRADABLE\n |\n |See [FPML](http://www.fpml.org/) for more examples.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "accountAttributeJson",
+ "success_response_body": "accountAttributeResponseJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAccountAttribute))"
+ }
+ },
+ "createProductCollection": {
+ "partial_function_name_raw": "nameOf(createProductCollection)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/product-collections/COLLECTION_CODE\"",
+ "summary": "\"Create Product Collection\"",
+ "description": "s\"\"\"Create or Update a Product Collection at the Bank.\n |\n |Use Product Collections to create Product \"Baskets\", \"Portfolios\", \"Indices\", \"Collections\", \"Underlyings-lists\", \"Buckets\" etc. etc.\n |\n |There is a many to many relationship between Products and Product Collections:\n |\n |* A Product can exist in many Collections\n |\n |* A Collection can contain many Products.\n |\n |A collection has collection code, one parent Product and one or more child Products.\n |\n |\n |$productHiearchyAndCollectionNote\n\n |${userAuthenticationMessage(true) }\n |\n |\n |\"\"\"",
+ "example_request_body": "putProductCollectionsV310",
+ "success_response_body": "productCollectionsJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProductCollection, apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canMaintainProductCollection))"
+ }
+ },
+ "getProductCollection": {
+ "partial_function_name_raw": "nameOf(getProductCollection)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/product-collections/COLLECTION_CODE\"",
+ "summary": "\"Get Product Collection\"",
+ "description": "s\"\"\"Returns information about the financial Product Collection specified by BANK_ID and COLLECTION_CODE:\n |\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productCollectionJsonTreeV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProductCollection, apiTagProduct)"
+ },
+ "deleteBranch": {
+ "partial_function_name_raw": "nameOf(deleteBranch)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/branches/BRANCH_ID\"",
+ "summary": "\"Delete Branch\"",
+ "description": "s\"\"\"Delete Branch from given Bank.\n |\n |${userAuthenticationMessage(true) }\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InsufficientAuthorisationToDeleteBranch,\n UnknownError\n )",
+ "tags": "List(apiTagBranch)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBranch,canDeleteBranchAtAnyBank))"
+ }
+ },
+ "createMeeting": {
+ "partial_function_name_raw": "\"createMeeting\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/meetings\"",
+ "summary": "\"Create Meeting (video conference/call)\"",
+ "description": "\"\"\"Create Meeting: Initiate a video conference/call with the bank.\n |\n |The Meetings resource contains meta data about video/other conference sessions\n |\n |provider_id determines the provider of the meeting / video chat service. MUST be url friendly (no spaces).\n |\n |purpose_id explains the purpose of the chat. onboarding | mortgage | complaint etc. MUST be url friendly (no spaces).\n |\n |Login is required.\n |\n |This call is **experimental**. Currently staff_user_id is not set. Further calls will be needed to correctly set this.\n \"\"\".stripMargin",
+ "example_request_body": "createMeetingJsonV310",
+ "success_response_body": "meetingJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMeeting, apiTagCustomer, apiTagExperimental)"
+ },
+ "getMeetings": {
+ "partial_function_name_raw": "\"getMeetings\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/meetings\"",
+ "summary": "\"Get Meetings\"",
+ "description": "\"\"\"Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.\n |\n |The actual conference/chats are handled by external services.\n |\n |Login is required.\n |\n |This call is **experimental** and will require further authorisation in the future.\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "meetingsJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError)",
+ "tags": "List(apiTagMeeting, apiTagCustomer, apiTagExperimental)"
+ },
+ "getMeeting": {
+ "partial_function_name_raw": "\"getMeeting\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/meetings/MEETING_ID\"",
+ "summary": "\"Get Meeting\"",
+ "description": "\"\"\"Get Meeting specified by BANK_ID / MEETING_ID\n |Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.\n |\n |The actual conference/chats are handled by external services.\n |\n |Login is required.\n |\n |This call is **experimental** and will require further authorisation in the future.\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "meetingJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n MeetingNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMeeting, apiTagCustomer, apiTagExperimental)"
+ },
+ "getServerJWK": {
+ "partial_function_name_raw": "\"getServerJWK\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/certs\"",
+ "summary": "\"Get JSON Web Key (JWK)\"",
+ "description": "\"\"\"Get the server's public JSON Web Key (JWK) set and certificate chain.\n | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "severJWK",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getMessageDocsSwagger": {
+ "partial_function_name_raw": "nameOf(getMessageDocsSwagger)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/message-docs/CONNECTOR/swagger2.0\"",
+ "summary": "\"Get Message Docs Swagger\"",
+ "description": "\"\"\"\n |This endpoint provides example message docs in swagger format.\n |It is only relavent for REST Connectors.\n |\n |This endpoint can be used by the developer building a REST Adapter that connects to the Core Banking System (CBS).\n |That is, the Adapter developer can use the Swagger surfaced here to build the REST APIs that the OBP REST connector will call to consume CBS services.\n |\n |i.e.:\n |\n |OBP API (Core OBP API code) -> OBP REST Connector (OBP REST Connector code) -> OBP REST Adapter (Adapter developer code) -> CBS (Main Frame)\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)"
+ },
+ "createConsentEmail": {
+ "partial_function_name_raw": "nameOf(createConsentEmail)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/my/consents/EMAIL\"",
+ "summary": "\"Create Consent (EMAIL)\"",
+ "description": "s\"\"\"\n |\n |This endpoint starts the process of creating a Consent.\n |\n |The Consent is created in an ${ConsentStatus.INITIATED} state.\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\",\"EMAIL\" or \"IMPLICIT\". \"EMAIL\" is used for testing purposes. OBP mapped mode \"IMPLICIT\" is \"EMAIL\".\n |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.\n |\n |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.\n |\n |$generalObpConsentText\n |\n |${userAuthenticationMessage(true)}\n |\n |Example 1:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n | \"phone_number\": \"+49 170 1234567\"\n |}\n |\n |Please note that consumer_id is optional field\n |Example 2:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"phone_number\": \"+49 170 1234567\"\n |}\n |\n |Please note if everything=false you need to explicitly specify views and entitlements\n |Example 3:\n |{\n | \"everything\": false,\n | \"views\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"account_id\": \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n | \"view_id\": \"${Constant.SYSTEM_OWNER_VIEW_ID}\"\n | }\n | ],\n | \"entitlements\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"role_name\": \"CanGetCustomersAtOneBank\"\n | }\n | ],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n | \"phone_number\": \"+49 170 1234567\"\n |}\n |\n |\"\"\"",
+ "example_request_body": "postConsentEmailJsonV310",
+ "success_response_body": "consentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "createConsentSms": {
+ "partial_function_name_raw": "nameOf(createConsentSms)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/my/consents/SMS\"",
+ "summary": "\"Create Consent (SMS)\"",
+ "description": "s\"\"\"\n |\n |This endpoint starts the process of creating a Consent.\n |\n |The Consent is created in an ${ConsentStatus.INITIATED} state.\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\",\"EMAIL\" or \"IMPLICIT\". \"EMAIL\" is used for testing purposes. OBP mapped mode \"IMPLICIT\" is \"EMAIL\".\n |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.\n |\n |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.\n |\n |$generalObpConsentText\n |\n |${userAuthenticationMessage(true)}\n |\n |Example 1:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n | \"email\": \"eveline@example.com\"\n |}\n |\n |Please note that consumer_id is optional field\n |Example 2:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"email\": \"eveline@example.com\"\n |}\n |\n |Please note if everything=false you need to explicitly specify views and entitlements\n |Example 3:\n |{\n | \"everything\": false,\n | \"views\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"account_id\": \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n | \"view_id\": \"${Constant.SYSTEM_OWNER_VIEW_ID}\"\n | }\n | ],\n | \"entitlements\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"role_name\": \"CanGetCustomersAtOneBank\"\n | }\n | ],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n | \"email\": \"eveline@example.com\"\n |}\n |\n |\"\"\"",
+ "example_request_body": "postConsentPhoneJsonV310",
+ "success_response_body": "consentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n MissingPropsValueAtThisInstance,\n SmsServerNotResponding,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "createConsentImplicit": {
+ "partial_function_name_raw": "nameOf(createConsentImplicit)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/my/consents/IMPLICIT\"",
+ "summary": "\"Create Consent (IMPLICIT)\"",
+ "description": "s\"\"\"\n |\n |This endpoint starts the process of creating a Consent.\n |\n |The Consent is created in an ${ConsentStatus.INITIATED} state.\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\",\"EMAIL\" or \"IMPLICIT\". \"EMAIL\" is used for testing purposes. OBP mapped mode \"IMPLICIT\" is \"EMAIL\".\n |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.\n |\n |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.\n |\n |$generalObpConsentText\n |\n |${userAuthenticationMessage(true)}\n |\n |Example 1:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n |}\n |\n |Please note that consumer_id is optional field\n |Example 2:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n |}\n |\n |Please note if everything=false you need to explicitly specify views and entitlements\n |Example 3:\n |{\n | \"everything\": false,\n | \"views\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"account_id\": \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n | \"view_id\": \"${Constant.SYSTEM_OWNER_VIEW_ID}\"\n | }\n | ],\n | \"entitlements\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"role_name\": \"CanGetCustomersAtOneBank\"\n | }\n | ],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n |}\n |\n |\"\"\"",
+ "example_request_body": "postConsentImplicitJsonV310",
+ "success_response_body": "consentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n MissingPropsValueAtThisInstance,\n SmsServerNotResponding,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "answerConsentChallenge": {
+ "partial_function_name_raw": "nameOf(answerConsentChallenge)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/consents/CONSENT_ID/challenge\"",
+ "summary": "\"Answer Consent Challenge\"",
+ "description": "s\"\"\"\n |\n |$generalObpConsentText\n |\n |\n |This endpoint is used to confirm a Consent previously created.\n |\n |The User must supply a code that was sent out of band (OOB) for example via an SMS.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PostConsentChallengeJsonV310(answer = \"12345678\")",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt = \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"INITIATED\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getConsents": {
+ "partial_function_name_raw": "\"getConsents\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/consents\"",
+ "summary": "\"Get Consents\"",
+ "description": "s\"\"\"\n |This endpoint gets the Consents that the current User created.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "revokeConsent": {
+ "partial_function_name_raw": "\"revokeConsent\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/consents/CONSENT_ID/revoke\"",
+ "summary": "\"Revoke Consent\"",
+ "description": "s\"\"\"\n |Revoke Consent for current user specified by CONSENT_ID\n |\n |There are a few reasons you might need to revoke an application’s access to a user’s account:\n | - The user explicitly wishes to revoke the application’s access\n | - You as the service provider have determined an application is compromised or malicious, and want to disable it\n | - etc.\n |\n |Please note that this endpoint only supports the case:: \"The user explicitly wishes to revoke the application’s access\"\n |\n |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.\n |The status of the token is changed to \"REVOKED\" so the next time the revoked client makes a request, their token will fail to validate.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "revokedConsentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "createUserAuthContextUpdateRequest": {
+ "partial_function_name_raw": "nameOf(createUserAuthContextUpdateRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/users/current/auth-context-updates/SCA_METHOD\"",
+ "summary": "\"Create User Auth Context Update Request\"",
+ "description": "s\"\"\"Create User Auth Context Update Request.\n |${userAuthenticationMessage(true)}\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\" or \"EMAIL\". \"EMAIL\" is used for testing purposes.\n |\n |\"\"\"",
+ "example_request_body": "postUserAuthContextJson",
+ "success_response_body": "userAuthContextUpdateJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n CreateUserAuthContextError,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "answerUserAuthContextUpdateChallenge": {
+ "partial_function_name_raw": "nameOf(answerUserAuthContextUpdateChallenge)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge\"",
+ "summary": "\"Answer Auth Context Update Challenge\"",
+ "description": "s\"\"\"\n |Answer Auth Context Update Challenge.\n |\"\"\"",
+ "example_request_body": "PostUserAuthContextUpdateJsonV310(answer = \"12345678\")",
+ "success_response_body": "userAuthContextUpdateJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagUser :: Nil"
+ },
+ "getSystemView": {
+ "partial_function_name_raw": "\"getSystemView\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Get System View\"",
+ "description": "s\"\"\"Get System View\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewJSONV220",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemView))"
+ }
+ },
+ "createSystemView": {
+ "partial_function_name_raw": "nameOf(createSystemView)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/system-views\"",
+ "summary": "\"Create System View\"",
+ "description": "s\"\"\"Create a system view\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the $canCreateSystemView entitlement.\n | The 'alias' field in the JSON can take one of two values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n | Please note that system views cannot be public. In case you try to set it you will get the error $SystemViewCannotBePublicError\n | \"\"\"",
+ "example_request_body": "SwaggerDefinitionsJSON.createSystemViewJsonV300",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSystemView))"
+ }
+ },
+ "deleteSystemView": {
+ "partial_function_name_raw": "\"deleteSystemView\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Delete System View\"",
+ "description": "\"Deletes the system view specified by VIEW_ID\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"user does not have owner access\"\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemView))"
+ }
+ },
+ "updateSystemView": {
+ "partial_function_name_raw": "nameOf(updateSystemView)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Update System View\"",
+ "description": "s\"\"\"Update an existing view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateSystemViewJson310",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSystemView))"
+ }
+ },
+ "getOAuth2ServerJWKsURIs": {
+ "partial_function_name_raw": "\"getOAuth2ServerJWKsURIs\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/jwks-uris\"",
+ "summary": "\"Get JSON Web Key (JWK) URIs\"",
+ "description": "\"\"\"Get the OAuth2 server's public JSON Web Key (JWK) URIs.\n | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "oAuth2ServerJwksUrisJson",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagOAuth, apiTagOIDC)"
+ },
+ "getMethodRoutings": {
+ "partial_function_name_raw": "nameOf(getMethodRoutings)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/method_routings\"",
+ "summary": "\"Get MethodRoutings\"",
+ "description": "s\"\"\"Get the all MethodRoutings.\n |\n |Query url parameters:\n |\n |* method_name: filter with method_name\n |* active: if active = true, it will show all the webui_ props. Even if they are set yet, we will return all the default webui_ props\n |\n |eg:\n |${getObpApiRoot}/v3.1.0/management/method_routings?active=true\n |${getObpApiRoot}/v3.1.0/management/method_routings?method_name=getBank\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"method_routings\",\n (List(MethodRoutingCommons(\"getBanks\", \"rest_vMar2019\", false, Some(\"some_bank_.*\"), List(MethodRoutingParam(\"url\", \"http://mydomain.com/xxx\")), Some(\"method-routing-id\"))))\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMethodRouting, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMethodRoutings))"
+ }
+ },
+ "createMethodRouting": {
+ "partial_function_name_raw": "nameOf(createMethodRouting)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/method_routings\"",
+ "summary": "\"Create MethodRouting\"",
+ "description": "s\"\"\"Create a MethodRouting.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |Explanation of Fields:\n |\n |* method_name is required String value, current supported value: $supportedConnectorNames\n |* connector_name is required String value\n |* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false\n |* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex\n |* parameters is optional array of key value pairs. You can set some parameters for this method\n |\n |note and CAVEAT!:\n |\n |* bank_id_pattern has to be empty for methods that do not take bank_id as a function parameter, otherwise might get empty result\n |* methods that aggregate bank objects (e.g. getBankAccountsForUser) have to take any existing method routings for these objects into consideration\n |* so if you create e.g. a bank specific method routing for getting an account, make sure that it is also served by endpoints getting ALL accounts for ALL banks\n |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = \"some\\\\-id_pattern_\\\\d+\"\n |\n |If the connector name starts with rest, parameters can contain \"outBoundMapping\" and \"inBoundMapping\", convert OutBound and InBound json structure.\n |for example:\n | outBoundMapping example, convert json from source to target:\n |\n |Build OutBound json value rules:\n |1 set cId value with: outboundAdapterCallContext.correlationId value\n |2 set bankId value with: concat bankId.value value with string helloworld\n |3 set originalJson value with: whole source json, note: the field value expression is $$root\n |\n |\n | inBoundMapping example, convert json from source to target:\n |\n |Build InBound json value rules:\n |1 and 2 set inboundAdapterCallContext and status value: because field name ends with \"$$default\", remove \"$$default\" from field name, not change the value\n |3 set fullName value with: concat string full: with result.name value\n |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0].\n |\"\"\"",
+ "example_request_body": "MethodRoutingCommons(\"getBank\", \"rest_vMar2019\", false, Some(\"some_bankId_.*\"), List(MethodRoutingParam(\"url\", \"http://mydomain.com/xxx\")))",
+ "success_response_body": "MethodRoutingCommons(\"getBank\", \"rest_vMar2019\", false, Some(\"some_bankId_.*\"),\n List(MethodRoutingParam(\"url\", \"http://mydomain.com/xxx\")),\n Some(\"this-method-routing-Id\")\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n InvalidConnectorName,\n InvalidConnectorMethodName,\n UnknownError\n )",
+ "tags": "List(apiTagMethodRouting, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateMethodRouting))"
+ }
+ },
+ "updateMethodRouting": {
+ "partial_function_name_raw": "nameOf(updateMethodRouting)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/method_routings/METHOD_ROUTING_ID\"",
+ "summary": "\"Update MethodRouting\"",
+ "description": "s\"\"\"Update a MethodRouting.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |Explaination of Fields:\n |\n |* method_name is required String value, current supported value: $supportedConnectorNames\n |* connector_name is required String value\n |* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false\n |* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex\n |* parameters is optional array of key value pairs. You can set some paremeters for this method\n |note:\n |\n |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = \"some\\\\-id_pattern_\\\\d+\"\n |\n |If connector name start with rest, parameters can contain \"outBoundMapping\" and \"inBoundMapping\", to convert OutBound and InBound json structure.\n |for example:\n | outBoundMapping example, convert json from source to target:\n |\n |Build OutBound json value rules:\n |1 set cId value with: outboundAdapterCallContext.correlationId value\n |2 set bankId value with: concat bankId.value value with string helloworld\n |3 set originalJson value with: whole source json, note: the field value expression is $$root\n |\n |\n | inBoundMapping example, convert json from source to target:\n |\n |Build InBound json value rules:\n |1 and 2 set inboundAdapterCallContext and status value: because field name ends with \"$$default\", remove \"$$default\" from field name, not change the value\n |3 set fullName value with: concat string full: with result.name value\n |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0].\n |\"\"\"",
+ "example_request_body": "MethodRoutingCommons(\"getBank\", \"rest_vMar2019\", true, Some(\"some_bankId\"), List(MethodRoutingParam(\"url\", \"http://mydomain.com/xxx\")))",
+ "success_response_body": "MethodRoutingCommons(\"getBank\", \"rest_vMar2019\", true, Some(\"some_bankId\"), List(MethodRoutingParam(\"url\", \"http://mydomain.com/xxx\")), Some(\"this-method-routing-Id\"))",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n InvalidConnectorName,\n InvalidConnectorMethodName,\n UnknownError\n )",
+ "tags": "List(apiTagMethodRouting, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateMethodRouting))"
+ }
+ },
+ "deleteMethodRouting": {
+ "partial_function_name_raw": "nameOf(deleteMethodRouting)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/method_routings/METHOD_ROUTING_ID\"",
+ "summary": "\"Delete MethodRouting\"",
+ "description": "s\"\"\"Delete a MethodRouting specified by METHOD_ROUTING_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMethodRouting, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteMethodRouting))"
+ }
+ },
+ "updateCustomerEmail": {
+ "partial_function_name_raw": "nameOf(updateCustomerEmail)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/email\"",
+ "summary": "\"Update the email of a Customer\"",
+ "description": "s\"\"\"Update an email of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerEmailJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerEmail :: Nil)"
+ }
+ },
+ "updateCustomerNumber": {
+ "partial_function_name_raw": "nameOf(updateCustomerNumber)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/number\"",
+ "summary": "\"Update the number of a Customer\"",
+ "description": "s\"\"\"Update the number of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerNumberJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerNumber :: Nil)"
+ }
+ },
+ "updateCustomerMobileNumber": {
+ "partial_function_name_raw": "nameOf(updateCustomerMobileNumber)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/mobile-number\"",
+ "summary": "\"Update the mobile number of a Customer\"",
+ "description": "s\"\"\"Update the mobile number of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerMobileNumberJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerMobilePhoneNumber :: Nil)"
+ }
+ },
+ "updateCustomerIdentity": {
+ "partial_function_name_raw": "nameOf(updateCustomerIdentity)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/identity\"",
+ "summary": "\"Update the identity data of a Customer\"",
+ "description": "s\"\"\"Update the identity data of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerIdentityJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerIdentity :: Nil)"
+ }
+ },
+ "updateCustomerCreditLimit": {
+ "partial_function_name_raw": "nameOf(updateCustomerCreditLimit)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/credit-limit\"",
+ "summary": "\"Update the credit limit of a Customer\"",
+ "description": "s\"\"\"Update the credit limit of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerCreditLimitJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerCreditLimit :: Nil)"
+ }
+ },
+ "updateCustomerCreditRatingAndSource": {
+ "partial_function_name_raw": "nameOf(updateCustomerCreditRatingAndSource)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/credit-rating-and-source\"",
+ "summary": "\"Update the credit rating and source of a Customer\"",
+ "description": "s\"\"\"Update the credit rating and source of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerCreditRatingAndSourceJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerCreditRatingAndSource :: canUpdateCustomerCreditRatingAndSourceAtAnyBank :: Nil)"
+ }
+ },
+ "updateAccount": {
+ "partial_function_name_raw": "nameOf(updateAccount)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Update Account\"",
+ "description": "s\"\"\"Update the account.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "updateAccountRequestJsonV310",
+ "success_response_body": "updateAccountResponseJsonV310",
+ "error_response_bodies": "List(InvalidJsonFormat, AuthenticatedUserIsRequired, UnknownError, BankAccountNotFound)",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAccount))"
+ }
+ },
+ "addCardForBank": {
+ "partial_function_name_raw": "nameOf(addCardForBank)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/cards\"",
+ "summary": "\"Create Card\"",
+ "description": "s\"\"\"Create Card at bank specified by BANK_ID .\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "createPhysicalCardJsonV310",
+ "success_response_body": "physicalCardJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n AllowedValuesAre,\n UnknownError\n )",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCardsForBank))"
+ }
+ },
+ "updatedCardForBank": {
+ "partial_function_name_raw": "nameOf(updatedCardForBank)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/cards/CARD_ID\"",
+ "summary": "\"Update Card\"",
+ "description": "s\"\"\"Update Card at bank specified by CARD_ID .\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "updatePhysicalCardJsonV310",
+ "success_response_body": "physicalCardJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n AllowedValuesAre,\n UnknownError\n )",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateCardsForBank))"
+ }
+ },
+ "getCardsForBank": {
+ "partial_function_name_raw": "nameOf(getCardsForBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/cards\"",
+ "summary": "\"Get Cards for the specified bank\"",
+ "description": "s\"\"\"Should be able to filter on the following fields\n |\n |eg:/management/banks/BANK_ID/cards?customer_id=66214b8e-259e-44ad-8868-3eb47be70646&account_id=8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\n |\n |1 customer_id should be valid customer_id, otherwise, it will return an empty card list.\n |\n |2 account_id should be valid account_id , otherwise, it will return an empty card list.\n |\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "physicalCardsJsonV310",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,BankNotFound, UnknownError)",
+ "tags": "List(apiTagCard)"
+ },
+ "getCardForBank": {
+ "partial_function_name_raw": "nameOf(getCardForBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/cards/CARD_ID\"",
+ "summary": "\"Get Card By Id\"",
+ "description": "s\"\"\"\n |This will the datails of the card.\n |It shows the account infomation which linked the the card.\n |Also shows the card attributes of the card.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "physicalCardWithAttributesJsonV310",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired,BankNotFound, UnknownError)",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCardsForBank))"
+ }
+ },
+ "deleteCardForBank": {
+ "partial_function_name_raw": "nameOf(deleteCardForBank)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/cards/CARD_ID\"",
+ "summary": "\"Delete Card\"",
+ "description": "s\"\"\"Delete a Card at bank specified by CARD_ID .\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n AllowedValuesAre,\n UnknownError\n )",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCardsForBank))"
+ }
+ },
+ "createCardAttribute": {
+ "partial_function_name_raw": "nameOf(createCardAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/cards/CARD_ID/attribute\"",
+ "summary": "\"Create Card Attribute\"",
+ "description": "s\"\"\" Create Card Attribute\n |\n |Card Attributes are used to describe a financial Product with a list of typed key value pairs.\n |\n |Each Card Attribute is linked to its Card by CARD_ID\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "CardAttributeJson(\n cardAttributeNameExample.value,\n CardAttributeType.DOUBLE.toString,\n cardAttributeValueExample.value\n )",
+ "success_response_body": "CardAttributeCommons(\n Some(BankId(bankIdExample.value)),\n Some(cardIdExample.value),\n Some(cardAttributeIdExample.value),\n cardAttributeNameExample.value,\n CardAttributeType.DOUBLE,\n cardAttributeValueExample.value)",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCard, apiTagCardAttribute, apiTagAttribute)"
+ },
+ "updateCardAttribute": {
+ "partial_function_name_raw": "nameOf(updateCardAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/cards/CARD_ID/attributes/CARD_ATTRIBUTE_ID\"",
+ "summary": "\"Update Card Attribute\"",
+ "description": "s\"\"\" Update Card Attribute\n |\n |Card Attributes are used to describe a financial Product with a list of typed key value pairs.\n |\n |Each Card Attribute is linked to its Card by CARD_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "CardAttributeJson(\n cardAttributeNameExample.value,\n CardAttributeType.DOUBLE.toString,\n cardAttributeValueExample.value\n )",
+ "success_response_body": "CardAttributeCommons(\n Some(BankId(bankIdExample.value)),\n Some(cardIdExample.value),\n Some(cardAttributeIdExample.value),\n cardAttributeNameExample.value,\n CardAttributeType.DOUBLE,\n cardAttributeValueExample.value)",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCard, apiTagCardAttribute, apiTagAttribute)"
+ },
+ "updateCustomerBranch": {
+ "partial_function_name_raw": "nameOf(updateCustomerBranch)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/branch\"",
+ "summary": "\"Update the Branch of a Customer\"",
+ "description": "s\"\"\"Update the Branch of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putCustomerBranchJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerIdentity :: Nil)"
+ }
+ },
+ "updateCustomerData": {
+ "partial_function_name_raw": "nameOf(updateCustomerData)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/data\"",
+ "summary": "\"Update the other data of a Customer\"",
+ "description": "s\"\"\"Update the other data of the Customer specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "putUpdateCustomerDataJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateCustomerIdentity :: Nil)"
+ }
+ },
+ "createAccount": {
+ "partial_function_name_raw": "\"createAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Create Account\"",
+ "description": "\"\"\"Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.\n |\n |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.\n |\n |If the PUT body USER_ID *is* specified, the logged in user must have the Role canCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.\n |\n |If the PUT body USER_ID is *not* specified, the account will be owned by the logged in User.\n |\n |The 'product_code' field SHOULD be a product_code from Product.\n |If the 'product_code' matches a product_code from Product, account attributes will be created that match the Product Attributes.\n |\n |Note: The Amount MUST be zero.\"\"\".stripMargin",
+ "example_request_body": "createAccountRequestJsonV310",
+ "success_response_body": "createAccountResponseJsonV310",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankNotFound,\n AuthenticatedUserIsRequired,\n InvalidUserId,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n UserNotFoundById,\n UserHasMissingRoles,\n InvalidAccountBalanceAmount,\n InvalidAccountInitialBalance,\n InitialBalanceMustBeZero,\n InvalidAccountBalanceCurrency,\n AccountIdAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagAccount,apiTagOnboarding)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccount))"
+ }
+ },
+ "getPrivateAccountByIdFull": {
+ "partial_function_name_raw": "nameOf(getPrivateAccountByIdFull)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Account by Id (Full)\"",
+ "description": "\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |* Available views (sorted by short_name)\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedAccountJSON310",
+ "error_response_bodies": "List(BankNotFound,AccountNotFound,ViewNotFound, UserNoPermissionAccessView, UnknownError)",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "saveHistoricalTransaction": {
+ "partial_function_name_raw": "nameOf(saveHistoricalTransaction)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/historical/transactions \"",
+ "summary": "\"Save Historical Transactions \"",
+ "description": "s\"\"\"\n |Import the historical transactions.\n |\n |The fields bank_id, account_id, counterparty_id in the json body are all optional ones.\n |It support transfer money from account to account, account to counterparty and counterparty to counterparty\n |Both bank_id + account_id and counterparty_id can identify the account, so OBP only need one of them to make the payment.\n |So:\n |When you need the account to account, just omit counterparty_id field.eg:\n |{\n | \"from\": {\n | \"bank_id\": \"gh.29.uk\",\n | \"account_id\": \"1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | },\n | \"to\": {\n | \"bank_id\": \"gh.29.uk\",\n | \"account_id\": \"2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | },\n | \"value\": {\n | \"currency\": \"GBP\",\n | \"amount\": \"10\"\n | },\n | \"description\": \"this is for work\",\n | \"posted\": \"2017-09-19T02:31:05Z\",\n | \"completed\": \"2017-09-19T02:31:05Z\",\n | \"type\": \"SANDBOX_TAN\",\n | \"charge_policy\": \"SHARED\"\n |}\n |\n |When you need the counterparty to counterparty, need to omit bank_id and account_id field.eg:\n |{\n | \"from\": {\n | \"counterparty_id\": \"f6392b7d-4218-45ea-b9a7-eaa71c0202f9\"\n | },\n | \"to\": {\n | \"counterparty_id\": \"26392b7d-4218-45ea-b9a7-eaa71c0202f9\"\n | },\n | \"value\": {\n | \"currency\": \"GBP\",\n | \"amount\": \"10\"\n | },\n | \"description\": \"this is for work\",\n | \"posted\": \"2017-09-19T02:31:05Z\",\n | \"completed\": \"2017-09-19T02:31:05Z\",\n | \"type\": \"SANDBOX_TAN\",\n | \"charge_policy\": \"SHARED\"\n |}\n |\n |or, you can counterparty to account\n |{\n | \"from\": {\n | \"counterparty_id\": \"f6392b7d-4218-45ea-b9a7-eaa71c0202f9\"\n | },\n | \"to\": {\n | \"bank_id\": \"gh.29.uk\",\n | \"account_id\": \"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | },\n | \"value\": {\n | \"currency\": \"GBP\",\n | \"amount\": \"10\"\n | },\n | \"description\": \"this is for work\",\n | \"posted\": \"2017-09-19T02:31:05Z\",\n | \"completed\": \"2017-09-19T02:31:05Z\",\n | \"type\": \"SANDBOX_TAN\",\n | \"charge_policy\": \"SHARED\"\n |}\n |\n |This call is experimental.\n \"\"\".stripMargin",
+ "example_request_body": "postHistoricalTransactionJson",
+ "success_response_body": "postHistoricalTransactionResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n CounterpartyNotFoundByCounterpartyId,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateHistoricalTransaction))"
+ }
+ },
+ "getWebUiProps": {
+ "partial_function_name_raw": "nameOf(getWebUiProps)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/webui_props\"",
+ "summary": "\"Get WebUiProps\"",
+ "description": "s\"\"\"\n |\n |Get WebUiProps - properties that configure the Web UI behavior and appearance.\n |\n |Properties with names starting with \"webui_\" can be stored in the database and managed via API.\n |\n |**Data Sources:**\n |\n |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.\n |\n |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.\n |\n |**Query Parameter:**\n |\n |* `active` (optional, boolean string, default: \"false\")\n | - If `active=false` or omitted: Returns only explicit props from the database\n | - If `active=true`: Returns explicit props + implicit (default) props from configuration file\n | - When both sources have the same property name, the database value takes precedence\n | - Implicit props are marked with `webUiPropsId = \"default\"`\n |\n |**Examples:**\n |\n |Get only database-stored props:\n |${getObpApiRoot}/v3.1.0/management/webui_props\n |\n |Get database props combined with defaults:\n |${getObpApiRoot}/v3.1.0/management/webui_props?active=true\n |\n |For more details about WebUI Props, including how to set config file defaults and precedence order, see ${Glossary.getGlossaryItemLink(\"webui_props\")}.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"webui_props\",\n (List(WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"web-ui-props-id\"))))\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetWebUiProps))"
+ }
+ },
+ "createWebUiProps": {
+ "partial_function_name_raw": "nameOf(createWebUiProps)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/webui_props\"",
+ "summary": "\"Create WebUiProps\"",
+ "description": "s\"\"\"Create a WebUiProps.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |Explaination of Fields:\n |\n |* name is required String value\n |* value is required String value\n |\n |The line break and double quotations should do escape, example:\n |\n |```\n |\n |{\"name\": \"webui_some\", \"value\": \"this value\n |have \"line break\" and double quotations.\"}\n |\n |```\n |should do escape like this:\n |\n |```\n |\n |{\"name\": \"webui_some\", \"value\": \"this value\\\\nhave \\\\\"line break\\\\\" and double quotations.\"}\n |\n |```\n |\n |Insert image examples:\n |\n |```\n |// set width=100 and height=50\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |// only set height=50\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |// only width=20%\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |```\n |\n |\"\"\"",
+ "example_request_body": "WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\")",
+ "success_response_body": "WebUiPropsCommons( \"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"some-web-ui-props-id\"))",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateWebUiProps))"
+ }
+ },
+ "deleteWebUiProps": {
+ "partial_function_name_raw": "nameOf(deleteWebUiProps)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/webui_props/WEB_UI_PROPS_ID\"",
+ "summary": "\"Delete WebUiProps\"",
+ "description": "s\"\"\"Delete a WebUiProps specified by WEB_UI_PROPS_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteWebUiProps))"
+ }
+ },
+ "getBankAccountsBalances": {
+ "partial_function_name_raw": "nameOf(getBankAccountsBalances)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/balances\"",
+ "summary": "\"Get Accounts Balances\"",
+ "description": "\"\"\"Get the Balances for the Accounts of the current User at one bank.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalancesV310Json",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "enableDisableConsumers": {
+ "partial_function_name_raw": "\"enableDisableConsumers\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Enable or Disable Consumers\"",
+ "description": "s\"\"\"Enable/Disable a Consumer specified by CONSUMER_ID.\n |\n |\"\"\"",
+ "example_request_body": "putEnabledJSON",
+ "success_response_body": "putEnabledJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canEnableConsumers,canDisableConsumers))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v4_0_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v4_0_0.json
new file mode 100644
index 0000000000..bc71a80cb8
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v4_0_0.json
@@ -0,0 +1,3347 @@
+{
+ "schema_version": 1,
+ "version": "v4_0_0",
+ "source_file": "obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 256,
+ "endpoints": {
+ "getMapperDatabaseInfo": {
+ "partial_function_name_raw": "nameOf(getMapperDatabaseInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/database/info\"",
+ "summary": "\"Get Mapper Database Info\"",
+ "description": "s\"\"\"Get basic information about the Mapper Database.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "adapterInfoJsonV300",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDatabaseInfo))"
+ }
+ },
+ "getLogoutLink": {
+ "partial_function_name_raw": "nameOf(\n getLogoutLink\n )",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/logout-link\"",
+ "summary": "\"Get Logout Link\"",
+ "description": "s\"\"\"Get the Logout Link\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "logoutLinkV400",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagUser)"
+ },
+ "callsLimit": {
+ "partial_function_name_raw": "nameOf(callsLimit)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/call-limits\"",
+ "summary": "\"Set Rate Limits / Call Limits per Consumer\"",
+ "description": "s\"\"\"\n |Set the API rate limits / call limits for a Consumer:\n |\n |Rate limiting can be set:\n |\n |Per Second\n |Per Minute\n |Per Hour\n |Per Week\n |Per Month\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "callLimitPostJsonV400",
+ "success_response_body": "callLimitPostJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagRateLimits)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateRateLimits))"
+ }
+ },
+ "getBanks": {
+ "partial_function_name_raw": "nameOf(getBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Get Banks\"",
+ "description": "\"\"\"Get banks on this API instance\n |Returns a list of banks supported on this server:\n |\n |* ID used as parameter in URLs\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "banksJSON400",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBank": {
+ "partial_function_name_raw": "nameOf(getBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID\"",
+ "summary": "\"Get Bank\"",
+ "description": "\"\"\"Get the bank specified by BANK_ID\n |Returns information about a single bank specified by BANK_ID including:\n |\n |* Short and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankJson400",
+ "error_response_bodies": "List(UnknownError, BankNotFound)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "ibanChecker": {
+ "partial_function_name_raw": "nameOf(ibanChecker)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/account/check/scheme/iban\"",
+ "summary": "\"Validate and check IBAN\"",
+ "description": "\"\"\"Validate and check IBAN for errors\n |\n |\"\"\"",
+ "example_request_body": "ibanCheckerPostJsonV400",
+ "success_response_body": "ibanCheckerJsonV400",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "getDoubleEntryTransaction": {
+ "partial_function_name_raw": "nameOf(getDoubleEntryTransaction)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/double-entry-transaction\"",
+ "summary": "\"Get Double Entry Transaction\"",
+ "description": "s\"\"\"Get Double Entry Transaction\n |\n |This endpoint can be used to see the double entry transactions. It returns the `bank_id`, `account_id` and `transaction_id`\n |for the debit end the credit transaction. The other side account can be a settlement account or an OBP account.\n |\n |The endpoint also provide the `transaction_request` object which contains the `bank_id`, `account_id` and\n |`transaction_request_id` of the transaction request at the origin of the transaction. Please note that if none\n |transaction request is at the origin of the transaction, the `transaction_request` object will be `null`.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "doubleEntryTransactionJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction)",
+ "extra_named_args": {
+ "roles": "Some(\n List(\n canGetDoubleEntryTransactionAtAnyBank,\n canGetDoubleEntryTransactionAtOneBank\n )\n )"
+ }
+ },
+ "getBalancingTransaction": {
+ "partial_function_name_raw": "nameOf(getBalancingTransaction)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/transactions/TRANSACTION_ID/balancing-transaction\"",
+ "summary": "\"Get Balancing Transaction\"",
+ "description": "s\"\"\"Get Balancing Transaction\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "doubleEntryTransactionJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "createSettlementAccount": {
+ "partial_function_name_raw": "nameOf(createSettlementAccount)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/settlement-accounts\"",
+ "summary": "\"Create Settlement Account\"",
+ "description": "s\"\"\"Create a new settlement account at a bank.\n |\n |The created settlement account id will be the concatenation of the payment system and the account currency.\n |For examples: SEPA_SETTLEMENT_ACCOUNT_EUR, CARD_SETTLEMENT_ACCOUNT_USD\n |\n |By default, when you create a new bank, two settlements accounts are created automatically: OBP_DEFAULT_INCOMING_ACCOUNT_ID and OBP_DEFAULT_OUTGOING_ACCOUNT_ID\n |Those two accounts have EUR as default currency.\n |\n |If you want to create default settlement account for a specific currency, you can fill the `payment_system` field with the `DEFAULT` value.\n |\n |When a transaction is saved in OBP through the mapped connector, OBP-API look for the account to save the double-entry transaction.\n |If no OBP account can be found from the counterparty, the double-entry transaction will be saved on a bank settlement account.\n |- First, the mapped connector looks for a settlement account specific to the payment system and currency. E.g SEPA_SETTLEMENT_ACCOUNT_EUR.\n |- If we don't find any specific settlement account with the payment system, we look for a default settlement account for the counterparty currency. E.g DEFAULT_SETTLEMENT_ACCOUNT_EUR.\n |- Else, we select one of the two OBP default settlement accounts (OBP_DEFAULT_INCOMING_ACCOUNT_ID/OBP_DEFAULT_OUTGOING_ACCOUNT_ID) according to the transaction direction.\n |\n |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.\n |\n |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User.\n |\n |Note: The Amount MUST be zero.\n |\"\"\".stripMargin",
+ "example_request_body": "settlementAccountRequestJson",
+ "success_response_body": "settlementAccountResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidAccountInitialBalance,\n InitialBalanceMustBeZero,\n InvalidISOCurrencyCode,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSettlementAccountAtOneBank))"
+ }
+ },
+ "getSettlementAccounts": {
+ "partial_function_name_raw": "nameOf(getSettlementAccounts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/settlement-accounts\"",
+ "summary": "\"Get Settlement accounts at Bank\"",
+ "description": "\"\"\"Get settlement accounts on this API instance\n |Returns a list of settlement accounts at this Bank\n |\n |Note: a settlement account is considered as a bank account.\n |So you can update it and add account attributes to it using the regular account endpoints\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "settlementAccountsJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagPsd2)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSettlementAccountAtOneBank))"
+ }
+ },
+ "createTransactionRequestAccount": {
+ "partial_function_name_raw": "\"createTransactionRequestAccount\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT/transaction-requests\"",
+ "summary": "\"Create Transaction Request (ACCOUNT)\"",
+ "description": "s\"\"\"When using ACCOUNT, the payee is set in the request body.\n |\n |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyJsonV200",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestAccountOtp": {
+ "partial_function_name_raw": "\"createTransactionRequestAccountOtp\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT_OTP/transaction-requests\"",
+ "summary": "\"Create Transaction Request (ACCOUNT_OTP)\"",
+ "description": "s\"\"\"When using ACCOUNT, the payee is set in the request body.\n |\n |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyJsonV200",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestCounterparty": {
+ "partial_function_name_raw": "\"createTransactionRequestCounterparty\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/COUNTERPARTY/transaction-requests\"",
+ "summary": "\"Create Transaction Request (COUNTERPARTY)\"",
+ "description": "s\"\"\"\n |$transactionRequestGeneralText\n |\n |When using a COUNTERPARTY to create a Transaction Request, specify the counterparty_id in the body of the request.\n |The routing details of the counterparty will be forwarded to the Core Banking System (CBS) for the transfer.\n |\n |COUNTERPARTY Transaction Requests are used for Variable Recurring Payments (VRP). Use the following ${Glossary\n .getApiExplorerLink(\n \"endpoint\",\n \"OBPv5.1.0-createVRPConsentRequest\"\n )} to create a consent for VRPs.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyCounterpartyJSON",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestSimple": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestSimple)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SIMPLE/transaction-requests\"",
+ "summary": "\"Create Transaction Request (SIMPLE)\"",
+ "description": "s\"\"\"\n |Special instructions for SIMPLE:\n |\n |You can transfer money to the Bank Account Number or IBAN directly.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodySimpleJsonV400",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestSepa": {
+ "partial_function_name_raw": "\"createTransactionRequestSepa\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SEPA/transaction-requests\"",
+ "summary": "\"Create Transaction Request (SEPA)\"",
+ "description": "s\"\"\"\n |Special instructions for SEPA:\n |\n |When using a SEPA Transaction Request, you specify the IBAN of a Counterparty in the body of the request.\n |The routing details (IBAN) of the counterparty will be forwarded to the core banking system for the transfer.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodySEPAJsonV400",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestRefund": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestRefund)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/REFUND/transaction-requests\"",
+ "summary": "\"Create Transaction Request (REFUND)\"",
+ "description": "s\"\"\"\n |\n |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded.\n |\n |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction.\n |In the `from` object, you have two choices :\n |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API\n |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API\n |\n |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent.\n |(This case is not managed by the OBP-API and require an external adapter)\n |\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyRefundJsonV400",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestFreeForm": {
+ "partial_function_name_raw": "\"createTransactionRequestFreeForm\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/FREE_FORM/transaction-requests\"",
+ "summary": "\"Create Transaction Request (FREE_FORM)\"",
+ "description": "s\"\"\"$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyFreeFormJSON",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAnyTransactionRequest))"
+ }
+ },
+ "createTransactionRequestAgentCashWithDrawal": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestAgentCashWithDrawal)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/AGENT_CASH_WITHDRAWAL/transaction-requests\"",
+ "summary": "\"Create Transaction Request (AGENT_CASH_WITHDRAWAL)\"",
+ "description": "s\"\"\"\n |\n |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded.\n |\n |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction.\n |In the `from` object, you have two choices :\n |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API\n |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API\n |\n |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent.\n |(This case is not managed by the OBP-API and require an external adapter)\n |\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyAgentJsonV400",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestCard": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestCard)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/transaction-request-types/CARD/transaction-requests\"",
+ "summary": "\"Create Transaction Request (CARD)\"",
+ "description": "s\"\"\"\n |\n |When using CARD, the payee is set in the request body .\n |\n |Money goes into the Counterparty in the request body.\n |\n |$transactionRequestGeneralText\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyCardJsonV400",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n AccountNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "answerTransactionRequestChallenge": {
+ "partial_function_name_raw": "\"answerTransactionRequestChallenge\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge\"",
+ "summary": "\"Answer Transaction Request Challenge\"",
+ "description": "s\"\"\"In Sandbox mode, any string that can be converted to a positive integer will be accepted as an answer.\n |\n |This endpoint totally depends on createTransactionRequest, it need get the following data from createTransactionRequest response body.\n |\n |1)`TRANSACTION_REQUEST_TYPE` : is the same as createTransactionRequest request URL .\n |\n |2)`TRANSACTION_REQUEST_ID` : is the `id` field in createTransactionRequest response body.\n |\n |3) `id` : is `challenge.id` field in createTransactionRequest response body.\n |\n |4) `answer` : must be `123` in case that Strong Customer Authentication method for OTP challenge is dummy.\n | For instance: SANDBOX_TAN_OTP_INSTRUCTION_TRANSPORT=dummy\n | Possible values are dummy,email and sms\n | In CBS mode, the answer can be got by phone message or other SCA methods.\n |\n |Note that each Transaction Request Type can have its own OTP_INSTRUCTION_TRANSPORT method.\n |OTP_INSTRUCTION_TRANSPORT methods are set in Props. See sample.props.template for instructions.\n |\n |Single or Multiple authorisations\n |\n |OBP allows single or multi party authorisations.\n |\n |Single party authorisation:\n |\n |In the case that only one person needs to authorise i.e. answer a security challenge we have the following change of state of a `transaction request`:\n | INITIATED => COMPLETED\n |\n |\n |Multiparty authorisation:\n |\n |In the case that multiple parties (n persons) need to authorise a transaction request i.e. answer security challenges, we have the followings state flow for a `transaction request`:\n | INITIATED => NEXT_CHALLENGE_PENDING => ... => NEXT_CHALLENGE_PENDING => COMPLETED\n |\n |The security challenge is bound to a user i.e. in the case of a correct answer but the user is different than expected the challenge will fail.\n |\n |Rule for calculating number of security challenges:\n |If Product Account attribute REQUIRED_CHALLENGE_ANSWERS=N then create N challenges\n |(one for every user that has a View where permission $CAN_ADD_TRANSACTION_REQUEST_TO_ANY_ACCOUNT=true)\n |In the case REQUIRED_CHALLENGE_ANSWERS is not defined as an account attribute, the default number of security challenges created is one.\n |\n \"\"\".stripMargin",
+ "example_request_body": "challengeAnswerJson400",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n InvalidAccountIdFormat,\n InvalidJsonFormat,\n $BankNotFound,\n $BankAccountNotFound,\n TransactionRequestStatusNotInitiated,\n TransactionRequestTypeHasChanged,\n AllowedAttemptsUsedUp,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestAttribute": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attribute\"",
+ "summary": "\"Create Transaction Request Attribute\"",
+ "description": "s\"\"\" Create Transaction Request Attribute\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionRequestAttributeJsonV400",
+ "success_response_body": "transactionRequestAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTransactionRequestAttributeAtOneBank))"
+ }
+ },
+ "getTransactionRequestAttributeById": {
+ "partial_function_name_raw": "nameOf(getTransactionRequestAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID\"",
+ "summary": "\"Get Transaction Request Attribute By Id\"",
+ "description": "s\"\"\" Get Transaction Request Attribute By Id\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionRequestAttributeAtOneBank))"
+ }
+ },
+ "getTransactionRequestAttributes": {
+ "partial_function_name_raw": "nameOf(getTransactionRequestAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes\"",
+ "summary": "\"Get Transaction Request Attributes\"",
+ "description": "s\"\"\" Get Transaction Request Attributes\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionRequestAttributesAtOneBank))"
+ }
+ },
+ "updateTransactionRequestAttribute": {
+ "partial_function_name_raw": "nameOf(updateTransactionRequestAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID\"",
+ "summary": "\"Update Transaction Request Attribute\"",
+ "description": "s\"\"\" Update Transaction Request Attribute\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionRequestAttributeJsonV400",
+ "success_response_body": "transactionRequestAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateTransactionRequestAttributeAtOneBank))"
+ }
+ },
+ "createOrUpdateTransactionRequestAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateTransactionRequestAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/transaction-request\"",
+ "summary": "\"Create or Update Transaction Request Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Transaction Request Attribute Definition\n |\n |The category field must be ${AttributeCategory.TransactionRequest}\n |\n |The type field must be one of: ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionRequestAttributeDefinitionJsonV400",
+ "success_response_body": "transactionRequestAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTransactionRequestAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getTransactionRequestAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getTransactionRequestAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/transaction-request\"",
+ "summary": "\"Get Transaction Request Attribute Definition\"",
+ "description": "s\"\"\" Get Transaction Request Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionRequestAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteTransactionRequestAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteTransactionRequestAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction-request\"",
+ "summary": "\"Delete Transaction Request Attribute Definition\"",
+ "description": "s\"\"\" Delete Transaction Request Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteTransactionRequestAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getSystemDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getSystemDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system-dynamic-entities\"",
+ "summary": "\"Get System Dynamic Entities\"",
+ "description": "s\"\"\"Get all System Dynamic Entities.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )} \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_entities\",\n List(dynamicEntityResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLevelDynamicEntities))"
+ }
+ },
+ "getBankLevelDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities\"",
+ "summary": "\"Get Bank Level Dynamic Entities\"",
+ "description": "s\"\"\"Get all the bank level Dynamic Entities for one bank.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )}\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_entities\",\n List(dynamicEntityResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities))"
+ }
+ },
+ "deleteSystemDynamicEntity": {
+ "partial_function_name_raw": "nameOf(deleteSystemDynamicEntity)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/system-dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Delete System Level Dynamic Entity\"",
+ "description": "s\"\"\"Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )}/\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemLevelDynamicEntity))"
+ }
+ },
+ "deleteBankLevelDynamicEntity": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelDynamicEntity)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Delete Bank Level Dynamic Entity\"",
+ "description": "s\"\"\"Delete a Bank Level DynamicEntity specified by DYNAMIC_ENTITY_ID.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )}/\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelDynamicEntity))"
+ }
+ },
+ "getMyDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getMyDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/dynamic-entities\"",
+ "summary": "\"Get My Dynamic Entities\"",
+ "description": "s\"\"\"Get all my Dynamic Entities (definitions I created).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"My-Dynamic-Entities\"\n )}\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_entities\",\n List(dynamicEntityResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)"
+ },
+ "deleteMyDynamicEntity": {
+ "partial_function_name_raw": "nameOf(deleteMyDynamicEntity)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Delete My Dynamic Entity\"",
+ "description": "s\"\"\"Delete my DynamicEntity specified by DYNAMIC_ENTITY_ID.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"My-Dynamic-Entities\"\n )}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)"
+ },
+ "resetPasswordUrl": {
+ "partial_function_name_raw": "nameOf(resetPasswordUrl)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/user/reset-password-url\"",
+ "summary": "\"Create password reset url\"",
+ "description": "s\"\"\"Create password reset url.\n |\n |\"\"\"",
+ "example_request_body": "PostResetPasswordUrlJsonV400(\n \"jobloggs\",\n \"jo@gmail.com\",\n \"74a8ebcc-10e4-4036-bef3-9835922246bf\"\n )",
+ "success_response_body": "ResetPasswordUrlJsonV400(\n \"https://apisandbox.openbankproject.com/user_mgt/reset_password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateResetPasswordUrl))"
+ }
+ },
+ "addAccount": {
+ "partial_function_name_raw": "nameOf(addAccount)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts\"",
+ "summary": "\"Create Account (POST)\"",
+ "description": "\"\"\"Create Account at bank specified by BANK_ID.\n |\n |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.\n |\n |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.\n |\n |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User.\n |\n |The 'product_code' field SHOULD be a product_code from Product.\n |If the product_code matches a product_code from Product, account attributes will be created that match the Product Attributes.\n |\n |Note: The Amount MUST be zero.\"\"\".stripMargin",
+ "example_request_body": "createAccountRequestJsonV310",
+ "success_response_body": "createAccountResponseJsonV310",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidAccountBalanceAmount,\n InvalidAccountInitialBalance,\n InitialBalanceMustBeZero,\n InvalidAccountBalanceCurrency,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccount))"
+ }
+ },
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Hosted at information\n |* Energy source information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJson400",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getCallContext": {
+ "partial_function_name_raw": "nameOf(getCallContext)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/development/call_context\"",
+ "summary": "\"Get the Call Context of a current call\"",
+ "description": "s\"\"\"Get the Call Context of the current call.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCallContext))"
+ }
+ },
+ "verifyRequestSignResponse": {
+ "partial_function_name_raw": "nameOf(verifyRequestSignResponse)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/development/echo/jws-verified-request-jws-signed-response\"",
+ "summary": "\"Verify Request and Sign Response of a current call\"",
+ "description": "s\"\"\"Verify Request and Sign Response of a current call.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(Nil)"
+ }
+ },
+ "updateAccountLabel": {
+ "partial_function_name_raw": "\"updateAccountLabel\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Update Account Label\"",
+ "description": "s\"\"\"Update the label for the account. The label is how the account is known to the account owner e.g. 'My savings account'\n |\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "updateAccountJsonV400",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError,\n $BankAccountNotFound,\n \"user does not have access to owner view on account\"\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "lockUser": {
+ "partial_function_name_raw": "nameOf(lockUser)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USERNAME/locks\"",
+ "summary": "\"Lock the user\"",
+ "description": "s\"\"\"\n |Lock a User.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userLockStatusJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByProviderAndUsername,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canLockUser))"
+ }
+ },
+ "createUserWithRoles": {
+ "partial_function_name_raw": "nameOf(createUserWithRoles)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/user-entitlements\"",
+ "summary": "\"Create (DAuth) User with Roles\"",
+ "description": "s\"\"\"\n |This endpoint is used as part of the DAuth solution to grant Entitlements for Roles to a smart contract on the blockchain.\n |\n |Put the smart contract address in username\n |\n |For provider use \"dauth\"\n |\n |This endpoint will create the User with username and provider if the User does not already exist.\n |\n |Then it will create Entitlements i.e. grant Roles to the User.\n |\n |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views)\n |\n |i.e. Entitlements are used to create / consume system or bank level resources where as views / account access are used to consume / create customer level resources.\n |\n |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. \"bank_id\":\"\"\n |\n |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. \"bank_id\":\"my-bank-id\"\n |\n |Note: The Roles actually granted will depend on the Roles that the calling user has.\n |\n |If you try to grant Entitlements to a user that already exist (duplicate entitilements) you will get an error.\n |\n |For information about DAuth see below:\n |\n |${getGlossaryItem(\"DAuth\")}\n |\n |\"\"\"",
+ "example_request_body": "postCreateUserWithRolesJsonV400",
+ "success_response_body": "entitlementsJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementIsBankRole,\n EntitlementIsSystemRole,\n EntitlementAlreadyExists,\n InvalidUserProvider,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser, apiTagDAuth)"
+ },
+ "getEntitlements": {
+ "partial_function_name_raw": "\"getEntitlements\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/entitlements\"",
+ "summary": "\"Get Entitlements for User\"",
+ "description": "s\"\"\"\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementsJsonV400",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyUserAtAnyBank))"
+ }
+ },
+ "getEntitlementsForBank": {
+ "partial_function_name_raw": "nameOf(getEntitlementsForBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/entitlements\"",
+ "summary": "\"Get Entitlements for One Bank\"",
+ "description": "s\"\"\"\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "entitlementsJsonV400",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForOneBank, canGetEntitlementsForAnyBank))"
+ }
+ },
+ "addTagForViewOnAccount": {
+ "partial_function_name_raw": "\"addTagForViewOnAccount\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags\"",
+ "summary": "\"Create a tag on account\"",
+ "description": "s\"\"\"Posts a tag about an account ACCOUNT_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |Authentication is required as the tag is linked with the user.\"\"\"",
+ "example_request_body": "postAccountTagJSON",
+ "success_response_body": "accountTagJSON",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n NoViewPermission,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccountMetadata, apiTagAccount)"
+ },
+ "deleteTagForViewOnAccount": {
+ "partial_function_name_raw": "\"deleteTagForViewOnAccount\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags/TAG_ID\"",
+ "summary": "\"Delete a tag on account\"",
+ "description": "s\"\"\"Deletes the tag TAG_ID about the account ACCOUNT_ID made on [view](#1_2_1-getViewsForBankAccount).\n |\n |${userAuthenticationMessage(true)}\n |\n |Authentication is required as the tag is linked with the user.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n NoViewPermission,\n ViewNotFound,\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccountMetadata, apiTagAccount)"
+ },
+ "getTagsForViewOnAccount": {
+ "partial_function_name_raw": "\"getTagsForViewOnAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags\"",
+ "summary": "\"Get tags on account\"",
+ "description": "s\"\"\"Returns the account ACCOUNT_ID tags made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID).\n |${userAuthenticationMessage(true)}\n |\n |Authentication is required as the tag is linked with the user.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountTagsJSON",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n NoViewPermission,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccountMetadata, apiTagAccount)"
+ },
+ "getCoreAccountById": {
+ "partial_function_name_raw": "nameOf(getCoreAccountById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/account\"",
+ "summary": "\"Get Account by Id (Core)\"",
+ "description": "s\"\"\"Information returned about the account specified by ACCOUNT_ID:\n |\n |* Number - The human readable account number given by the bank that identifies the account.\n |* Label - A label given by the owner of the account\n |* Owners - Users that own this account\n |* Type - The type of account\n |* Balance - Currency and Value\n |* Account Routings - A list that might include IBAN or national account identifiers\n |* Account Rules - A list that might include Overdraft and other bank specific rules\n |* Tags - A list of Tags assigned to this account\n |\n |This call returns the owner view and requires access to that view.\n |\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountJsonV400",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, $BankAccountNotFound, UnknownError)",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getPrivateAccountByIdFull": {
+ "partial_function_name_raw": "nameOf(getPrivateAccountByIdFull)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Account by Id (Full)\"",
+ "description": "\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* IBAN\n |* Available views (sorted by short_name)\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedAccountJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "getAccountByAccountRouting": {
+ "partial_function_name_raw": "nameOf(getAccountByAccountRouting)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/accounts/account-routing-query\"",
+ "summary": "\"Get Account by Account Routing\"",
+ "description": "\"\"\"This endpoint returns the account (if it exists) linked with the provided scheme and address.\n |\n |The `bank_id` field is optional, but if it's not provided, we don't guarantee that the returned account is unique across all the banks.\n |\n |Example of account routing scheme: `IBAN`, \"OBP\", \"AccountNumber\", ...\n |Example of account routing address: `DE17500105178275645584`, \"321774cc-fccd-11ea-adc1-0242ac120002\", \"55897106215\", ...\n |\n |\"\"\".stripMargin",
+ "example_request_body": "bankAccountRoutingJson",
+ "success_response_body": "moderatedAccountJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "getAccountsByAccountRoutingRegex": {
+ "partial_function_name_raw": "nameOf(getAccountsByAccountRoutingRegex)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/accounts/account-routing-regex-query\"",
+ "summary": "\"Get Accounts by Account Routing Regex\"",
+ "description": "\"\"\"This endpoint returns an array of accounts matching the provided routing scheme and the routing address regex.\n |\n |The `bank_id` field is optional.\n |\n |Example of account routing scheme: `IBAN`, `OBP`, `AccountNumber`, ...\n |Example of account routing address regex: `DE175.*`, `55897106215-[A-Z]{3}`, ...\n |\n |This endpoint can be used to retrieve multiples accounts matching a same account routing address pattern.\n |For example, if you want to link multiple accounts having different currencies, you can create an account\n |with `123456789-EUR` as Account Number and an other account with `123456789-USD` as Account Number.\n |So we can identify the Account Number as `123456789`, so to get all the accounts with the same account number\n |and the different currencies, we can use this body in the request :\n |\n |```\n |{\n | \"bank_id\": \"BANK_ID\",\n | \"account_routing\": {\n | \"scheme\": \"AccountNumber\",\n | \"address\": \"123456789-[A-Z]{3}\"\n | }\n |}\n |```\n |\n |This request will returns the accounts matching the routing address regex (`123456789-EUR` and `123456789-USD`).\n |\n |\"\"\".stripMargin",
+ "example_request_body": "bankAccountRoutingJson",
+ "success_response_body": "moderatedAccountsJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "getBankAccountsBalancesForCurrentUser": {
+ "partial_function_name_raw": "nameOf(getBankAccountsBalancesForCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/balances\"",
+ "summary": "\"Get Accounts Balances\"",
+ "description": "\"\"\"Get the Balances for the Accounts of the current User at one bank.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalancesV400Json",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError)",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBankAccountBalancesForCurrentUser": {
+ "partial_function_name_raw": "nameOf(getBankAccountBalancesForCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances\"",
+ "summary": "\"Get Account Balances\"",
+ "description": "\"\"\"Get the Balances for one Account of the current User at one bank.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalanceV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CannotFindAccountAccess,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getFirehoseAccountsAtOneBank": {
+ "partial_function_name_raw": "nameOf(getFirehoseAccountsAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/firehose/accounts/views/VIEW_ID\"",
+ "summary": "\"Get Firehose Accounts at Bank\"",
+ "description": "s\"\"\"\n |Get all Accounts at a Bank.\n |\n |This endpoint allows bulk access to all accounts at the specified bank.\n |\n |Requires the CanUseFirehoseAtAnyBank Role or CanUseAccountFirehose Role\n |\n |Returns all accounts at the bank. The VIEW_ID parameter determines what account data fields are visible according to the view's permissions.\n |\n |The view specified must have is_firehose = true\n |\n |For VIEW_ID try 'owner' or 'firehose'\n |\n |Optional request parameters for filtering by account attributes:\n |URL params example:\n | /banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1\n |\n |To invalidate browser cache, add timestamp query parameter as follows (the parameter name must be `_timestamp_`):\n |URL params example:\n | `/banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1&_timestamp_=1596762180358`\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedFirehoseAccountsJsonV400",
+ "error_response_bodies": "List($BankNotFound)",
+ "tags": "List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData)",
+ "extra_named_args": {
+ "roles": "Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))"
+ }
+ },
+ "getFastFirehoseAccountsAtOneBank": {
+ "partial_function_name_raw": "nameOf(getFastFirehoseAccountsAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/fast-firehose/accounts\"",
+ "summary": "\"Get Fast Firehose Accounts at Bank\"",
+ "description": "s\"\"\"\n |\n |This endpoint allows bulk access to accounts.\n |\n |optional pagination parameters for filter with accounts\n |${urlParametersDocument(true, false)}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "fastFirehoseAccountsJsonV400",
+ "error_response_bodies": "List($BankNotFound)",
+ "tags": "List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData)",
+ "extra_named_args": {
+ "roles": "Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose))"
+ }
+ },
+ "getCustomersByCustomerPhoneNumber": {
+ "partial_function_name_raw": "nameOf(getCustomersByCustomerPhoneNumber)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/search/customers/mobile-phone-number\"",
+ "summary": "\"Get Customers by MOBILE_PHONE_NUMBER\"",
+ "description": "s\"\"\"Gets the Customers specified by MOBILE_PHONE_NUMBER.\n |\n |There are two wildcards often used in conjunction with the LIKE operator:\n | % - The percent sign represents zero, one, or multiple characters\n | _ - The underscore represents a single character\n |For example {\"customer_phone_number\":\"%381%\"} lists all numbers which contain 381 sequence\n |\n |\"\"\"",
+ "example_request_body": "postCustomerPhoneNumberJsonV400",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCurrentUserId": {
+ "partial_function_name_raw": "nameOf(getCurrentUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/user_id\"",
+ "summary": "\"Get User Id (Current)\"",
+ "description": "s\"\"\"Get the USER_ID of the logged in user\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userIdJsonV400",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagUser)"
+ },
+ "getUserByUserId": {
+ "partial_function_name_raw": "nameOf(getUserByUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/user_id/USER_ID\"",
+ "summary": "\"Get User by USER_ID\"",
+ "description": "s\"\"\"Get user by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundById,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUserByUsername": {
+ "partial_function_name_raw": "nameOf(getUserByUsername)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/username/USERNAME\"",
+ "summary": "\"Get User by USERNAME\"",
+ "description": "s\"\"\"Get user by USERNAME\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByProviderAndUsername,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUsersByEmail": {
+ "partial_function_name_raw": "nameOf(getUsersByEmail)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/email/USER_EMAIL/terminator\"",
+ "summary": "\"Get Users by Email Address\"",
+ "description": "s\"\"\"Get users by email address\n |\n |${userAuthenticationMessage(true)}\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByEmail,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUsers": {
+ "partial_function_name_raw": "nameOf(getUsers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Get all Users\"",
+ "description": "s\"\"\"Get all users\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required,\n |\n |${urlParametersDocument(false, false)}\n |* locked_status (if null ignore)\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "createUserInvitation": {
+ "partial_function_name_raw": "nameOf(createUserInvitation)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/user-invitation\"",
+ "summary": "\"Create User Invitation\"",
+ "description": "s\"\"\"Create User Invitation.\n |\n | This endpoint will send an invitation email to the developers, then they can use the link to create the obp user.\n |\n | purpose filed only support:${UserInvitationPurpose.values\n .toString()}.\n |\n | You can customise the email details use the following webui props:\n |\n | when purpose == ${UserInvitationPurpose.DEVELOPER.toString}\n | webui_developer_user_invitation_email_subject\n | webui_developer_user_invitation_email_from\n | webui_developer_user_invitation_email_text\n | webui_developer_user_invitation_email_html_text\n |\n | when purpose = == ${UserInvitationPurpose.CUSTOMER.toString}\n | webui_customer_user_invitation_email_subject\n | webui_customer_user_invitation_email_from\n | webui_customer_user_invitation_email_text\n | webui_customer_user_invitation_email_html_text\n |\n |\"\"\"",
+ "example_request_body": "userInvitationPostJsonV400",
+ "success_response_body": "userInvitationJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagUserInvitation, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(canCreateUserInvitation :: Nil)"
+ }
+ },
+ "getUserInvitationAnonymous": {
+ "partial_function_name_raw": "nameOf(getUserInvitationAnonymous)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/user-invitations\"",
+ "summary": "\"Get User Invitation Information\"",
+ "description": "s\"\"\"Get User Invitation Information.\n |\n |${userAuthenticationMessage(false)}\n |\"\"\"",
+ "example_request_body": "PostUserInvitationAnonymousJsonV400(secret_key = 5819479115482092878L)",
+ "success_response_body": "userInvitationJsonV400",
+ "error_response_bodies": "List(\n $BankNotFound,\n UserCustomerLinksNotFoundForUser,\n CannotGetUserInvitation,\n CannotFindUserInvitation,\n UnknownError\n )",
+ "tags": "List(apiTagUserInvitation, apiTagKyc)"
+ },
+ "getUserInvitation": {
+ "partial_function_name_raw": "nameOf(getUserInvitation)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/user-invitations/SECRET_LINK\"",
+ "summary": "\"Get User Invitation\"",
+ "description": "s\"\"\" Get User Invitation\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userInvitationJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUserInvitation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserInvitation))"
+ }
+ },
+ "getUserInvitations": {
+ "partial_function_name_raw": "nameOf(getUserInvitations)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/user-invitations\"",
+ "summary": "\"Get User Invitations\"",
+ "description": "s\"\"\" Get User Invitations\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userInvitationJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUserInvitation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserInvitation))"
+ }
+ },
+ "deleteUser": {
+ "partial_function_name_raw": "nameOf(deleteUser)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID\"",
+ "summary": "\"Delete a User\"",
+ "description": "s\"\"\"Delete a User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteUser))"
+ }
+ },
+ "createBank": {
+ "partial_function_name_raw": "\"createBank\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Create Bank\"",
+ "description": "s\"\"\"Create a new bank (Authenticated access).\n |\n |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.\n |Thus the User can manage the bank they create and assign Roles to other Users.\n |\n |Only SANDBOX mode (i.e. when connector=mapped in properties file)\n |The settlement accounts are automatically created by the system when the bank is created.\n |Name and account id are created in accordance to the next rules:\n | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)\n | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)\n |\n |\"\"\"",
+ "example_request_body": "postBankJson400",
+ "success_response_body": "bankJson400",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n InsufficientAuthorisationToCreateBank,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBank))"
+ }
+ },
+ "createDirectDebit": {
+ "partial_function_name_raw": "nameOf(createDirectDebit)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/direct-debit\"",
+ "summary": "\"Create Direct Debit\"",
+ "description": "s\"\"\"Create direct debit for an account.\n |\n |\"\"\"",
+ "example_request_body": "postDirectDebitJsonV400",
+ "success_response_body": "directDebitJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n NoViewPermission,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserNotFoundByUserId,\n CounterpartyNotFoundByCounterpartyId,\n UnknownError\n )",
+ "tags": "List(apiTagDirectDebit, apiTagAccount)"
+ },
+ "createDirectDebitManagement": {
+ "partial_function_name_raw": "nameOf(createDirectDebitManagement)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/direct-debit\"",
+ "summary": "\"Create Direct Debit (management)\"",
+ "description": "s\"\"\"Create direct debit for an account.\n |\n |\"\"\"",
+ "example_request_body": "postDirectDebitJsonV400",
+ "success_response_body": "directDebitJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n NoViewPermission,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserNotFoundByUserId,\n CounterpartyNotFoundByCounterpartyId,\n UnknownError\n )",
+ "tags": "List(apiTagDirectDebit, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateDirectDebitAtOneBank))"
+ }
+ },
+ "createStandingOrder": {
+ "partial_function_name_raw": "nameOf(createStandingOrder)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/standing-order\"",
+ "summary": "\"Create Standing Order\"",
+ "description": "s\"\"\"Create standing order for an account.\n |\n |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’}\n |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}}\n |\n |\"\"\"",
+ "example_request_body": "postStandingOrderJsonV400",
+ "success_response_body": "standingOrderJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n NoViewPermission,\n InvalidJsonFormat,\n InvalidNumber,\n InvalidISOCurrencyCode,\n CustomerNotFoundByCustomerId,\n UserNotFoundByUserId,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagStandingOrder, apiTagAccount)"
+ },
+ "createStandingOrderManagement": {
+ "partial_function_name_raw": "nameOf(createStandingOrderManagement)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/standing-order\"",
+ "summary": "\"Create Standing Order (management)\"",
+ "description": "s\"\"\"Create standing order for an account.\n |\n |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’}\n |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}}\n |\n |\n |\"\"\"",
+ "example_request_body": "postStandingOrderJsonV400",
+ "success_response_body": "standingOrderJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n NoViewPermission,\n InvalidJsonFormat,\n InvalidNumber,\n InvalidISOCurrencyCode,\n CustomerNotFoundByCustomerId,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagStandingOrder, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateStandingOrderAtOneBank))"
+ }
+ },
+ "grantUserAccessToView": {
+ "partial_function_name_raw": "\"grantUserAccessToView\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/grant\"",
+ "summary": "\"Grant User access to View\"",
+ "description": "s\"\"\"Grants the User identified by USER_ID access to the view identified by VIEW_ID.\n |\n |${userAuthenticationMessage(\n true\n )} and the user needs to be account holder.\n |\n |\"\"\"",
+ "example_request_body": "postAccountAccessJsonV400",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserLacksPermissionCanGrantAccessToViewForTargetAccount,\n InvalidJsonFormat,\n UserNotFoundById,\n SystemViewNotFound,\n ViewNotFound,\n CannotGrantAccountAccess,\n UnknownError\n )",
+ "tags": "List(\n apiTagAccountAccess,\n apiTagView,\n apiTagAccount,\n apiTagUser,\n apiTagOwnerRequired\n )"
+ },
+ "createUserWithAccountAccess": {
+ "partial_function_name_raw": "nameOf(createUserWithAccountAccess)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/user-account-access\"",
+ "summary": "\"Create (DAuth) User with Account Access\"",
+ "description": "s\"\"\"This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain.\n |\n |Put the smart contract address in username\n |\n |For provider use \"dauth\"\n |\n |This endpoint will create the (DAuth) User with username and provider if the User does not already exist.\n |\n |${userAuthenticationMessage(\n true\n )} and the logged in user needs to be account holder.\n |\n |For information about DAuth see below:\n |\n |${getGlossaryItem(\"DAuth\")}\n |\n |\"\"\"",
+ "example_request_body": "postCreateUserAccountAccessJsonV400",
+ "success_response_body": "List(viewJsonV300)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserLacksPermissionCanGrantAccessToViewForTargetAccount,\n InvalidJsonFormat,\n SystemViewNotFound,\n ViewNotFound,\n CannotGrantAccountAccess,\n UnknownError\n )",
+ "tags": "List(\n apiTagAccountAccess,\n apiTagView,\n apiTagAccount,\n apiTagUser,\n apiTagOwnerRequired,\n apiTagDAuth\n )"
+ },
+ "revokeUserAccessToView": {
+ "partial_function_name_raw": "\"revokeUserAccessToView\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/revoke\"",
+ "summary": "\"Revoke User access to View\"",
+ "description": "s\"\"\"Revoke the User identified by USER_ID access to the view identified by VIEW_ID.\n |\n |${userAuthenticationMessage(\n true\n )} and the user needs to be account holder.\n |\n |\"\"\"",
+ "example_request_body": "postAccountAccessJsonV400",
+ "success_response_body": "revokedJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserLacksPermissionCanRevokeAccessToViewForTargetAccount,\n InvalidJsonFormat,\n UserNotFoundById,\n SystemViewNotFound,\n ViewNotFound,\n CannotRevokeAccountAccess,\n CannotFindAccountAccess,\n UnknownError\n )",
+ "tags": "List(\n apiTagAccountAccess,\n apiTagView,\n apiTagAccount,\n apiTagUser,\n apiTagOwnerRequired\n )"
+ },
+ "revokeGrantUserAccessToViews": {
+ "partial_function_name_raw": "\"revokeGrantUserAccessToViews\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access\"",
+ "summary": "\"Revoke/Grant User access to View\"",
+ "description": "s\"\"\"Revoke/Grant the logged in User access to the views identified by json.\n |\n |${userAuthenticationMessage(\n true\n )} and the user needs to be an account holder or has owner view access.\n |\n |\"\"\"",
+ "example_request_body": "postRevokeGrantAccountAccessJsonV400",
+ "success_response_body": "revokedJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserLacksPermissionCanGrantAccessToViewForTargetAccount,\n InvalidJsonFormat,\n UserNotFoundById,\n SystemViewNotFound,\n ViewNotFound,\n CannotRevokeAccountAccess,\n CannotFindAccountAccess,\n UnknownError\n )",
+ "tags": "List(\n apiTagAccountAccess,\n apiTagView,\n apiTagAccount,\n apiTagUser,\n apiTagOwnerRequired\n )"
+ },
+ "createCustomerAttribute": {
+ "partial_function_name_raw": "nameOf(createCustomerAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/attribute\"",
+ "summary": "\"Create Customer Attribute\"",
+ "description": "s\"\"\" Create Customer Attribute\n |\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "customerAttributeJsonV400",
+ "success_response_body": "customerAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(\n List(\n canCreateCustomerAttributeAtOneBank,\n canCreateCustomerAttributeAtAnyBank\n )\n )"
+ }
+ },
+ "updateCustomerAttribute": {
+ "partial_function_name_raw": "nameOf(updateCustomerAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID\"",
+ "summary": "\"Update Customer Attribute\"",
+ "description": "s\"\"\" Update Customer Attribute\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "customerAttributeJsonV400",
+ "success_response_body": "customerAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(\n List(\n canUpdateCustomerAttributeAtOneBank,\n canUpdateCustomerAttributeAtAnyBank\n )\n )"
+ }
+ },
+ "getCustomerAttributes": {
+ "partial_function_name_raw": "nameOf(getCustomerAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/attributes\"",
+ "summary": "\"Get Customer Attributes\"",
+ "description": "s\"\"\" Get Customer Attributes\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(\n List(\n canGetCustomerAttributesAtOneBank,\n canGetCustomerAttributesAtAnyBank\n )\n )"
+ }
+ },
+ "getCustomerAttributeById": {
+ "partial_function_name_raw": "nameOf(getCustomerAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/attributes/ATTRIBUTE_ID\"",
+ "summary": "\"Get Customer Attribute By Id\"",
+ "description": "s\"\"\" Get Customer Attribute By Id\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(\n List(canGetCustomerAttributeAtOneBank, canGetCustomerAttributeAtAnyBank)\n )"
+ }
+ },
+ "getCustomersByAttributes": {
+ "partial_function_name_raw": "nameOf(getCustomersByAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Get Customers by ATTRIBUTES\"",
+ "description": "s\"\"\"Gets the Customers specified by attributes\n |\n |URL params example: /banks/some-bank-id/customers?name=John&age=8\n |URL params example: /banks/some-bank-id/customers?&limit=50&offset=1\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"customers\",\n List(customerWithAttributesJsonV310)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "createTransactionAttribute": {
+ "partial_function_name_raw": "nameOf(createTransactionAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attribute\"",
+ "summary": "\"Create Transaction Attribute\"",
+ "description": "s\"\"\" Create Transaction Attribute\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionAttributeJsonV400",
+ "success_response_body": "transactionAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTransactionAttributeAtOneBank))"
+ }
+ },
+ "updateTransactionAttribute": {
+ "partial_function_name_raw": "nameOf(updateTransactionAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ACCOUNT_ATTRIBUTE_ID\"",
+ "summary": "\"Update Transaction Attribute\"",
+ "description": "s\"\"\" Update Transaction Attribute\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionAttributeJsonV400",
+ "success_response_body": "transactionAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateTransactionAttributeAtOneBank))"
+ }
+ },
+ "getTransactionAttributes": {
+ "partial_function_name_raw": "nameOf(getTransactionAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes\"",
+ "summary": "\"Get Transaction Attributes\"",
+ "description": "s\"\"\" Get Transaction Attributes\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionAttributesAtOneBank))"
+ }
+ },
+ "getTransactionAttributeById": {
+ "partial_function_name_raw": "nameOf(getTransactionAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ATTRIBUTE_ID\"",
+ "summary": "\"Get Transaction Attribute By Id\"",
+ "description": "s\"\"\" Get Transaction Attribute By Id\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionAttributeAtOneBank))"
+ }
+ },
+ "createHistoricalTransactionAtBank": {
+ "partial_function_name_raw": "nameOf(createHistoricalTransactionAtBank)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/management/historical/transactions\"",
+ "summary": "\"Create Historical Transactions \"",
+ "description": "s\"\"\"\n |Create historical transactions at one Bank\n |\n |Use this endpoint to create transactions between any two accounts at the same bank.\n |From account and to account must be at the same bank.\n |Example:\n |{\n | \"from_account_id\": \"1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | \"to_account_id\": \"2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n | \"value\": {\n | \"currency\": \"GBP\",\n | \"amount\": \"10\"\n | },\n | \"description\": \"this is for work\",\n | \"posted\": \"2017-09-19T02:31:05Z\",\n | \"completed\": \"2017-09-19T02:31:05Z\",\n | \"type\": \"SANDBOX_TAN\",\n | \"charge_policy\": \"SHARED\"\n |}\n |\n |This call is experimental.\n \"\"\".stripMargin",
+ "example_request_body": "postHistoricalTransactionAtBankJson",
+ "success_response_body": "postHistoricalTransactionResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankNotFound,\n AccountNotFound,\n CounterpartyNotFoundByCounterpartyId,\n InvalidNumber,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateHistoricalTransactionAtBank))"
+ }
+ },
+ "getTransactionRequest": {
+ "partial_function_name_raw": "nameOf(getTransactionRequest)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests/TRANSACTION_REQUEST_ID\"",
+ "summary": "\"Get Transaction Request.\"",
+ "description": "\"\"\"Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID and for account specified by ACCOUNT_ID at bank specified by BANK_ID.\n |\n |The VIEW_ID specified must be 'owner' and the user must have access to this view.\n |\n |Version 2.0.0 now returns charge information.\n |\n |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:\n |\n |* Transaction Request Id\n |* Type\n |* Status (INITIATED, COMPLETED)\n |* Challenge (in order to confirm the request)\n |* From Bank / Account\n |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)\n |* Related Transactions\n |\n |PSD2 Context: PSD2 requires transparency of charges to the customer.\n |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.\n |The customer can proceed with the Transaction by answering the security challenge.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n GetTransactionRequestsException,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "getPrivateAccountsAtOneBank": {
+ "partial_function_name_raw": "\"getPrivateAccountsAtOneBank\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts\"",
+ "summary": "\"Get Accounts at Bank\"",
+ "description": "s\"\"\"\n |Returns the list of accounts at BANK_ID that the user has access to.\n |For each account the API returns the account ID and the views available to the user..\n |Each account must have at least one private View.\n |\n |optional request parameters for filter with attributes\n |URL params example: /banks/some-bank-id/accounts?&limit=50&offset=1\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "basicAccountsJSON",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError)",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPublicData)"
+ },
+ "createConsumer": {
+ "partial_function_name_raw": "\"createConsumer\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Post a Consumer\"",
+ "description": "s\"\"\"Create a Consumer (Authenticated access).\n |\n |\"\"\"",
+ "example_request_body": "ConsumerPostJSON(\n \"Test\",\n \"Web\",\n \"Description\",\n \"some@email.com\",\n \"redirecturl\",\n \"createdby\",\n true,\n new Date(),\n \"\"\"-----BEGIN CERTIFICATE-----\n |client_certificate_content\n |-----END CERTIFICATE-----\"\"\".stripMargin\n )",
+ "success_response_body": "consumerJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateConsumer))"
+ }
+ },
+ "getCustomersAtAnyBank": {
+ "partial_function_name_raw": "nameOf(getCustomersAtAnyBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers\"",
+ "summary": "\"Get Customers at Any Bank\"",
+ "description": "s\"\"\"Get Customers at Any Bank.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtAllBanks))"
+ }
+ },
+ "getCustomersMinimalAtAnyBank": {
+ "partial_function_name_raw": "nameOf(getCustomersMinimalAtAnyBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers-minimal\"",
+ "summary": "\"Get Customers Minimal at Any Bank\"",
+ "description": "s\"\"\"Get Customers Minimal at Any Bank.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersMinimalJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersMinimalAtAllBanks))"
+ }
+ },
+ "getScopes": {
+ "partial_function_name_raw": "nameOf(getScopes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumers/CONSUMER_ID/scopes\"",
+ "summary": "\"Get Scopes for Consumer\"",
+ "description": "s\"\"\"Get all the scopes for an consumer specified by CONSUMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "scopeJsons",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n EntitlementNotFound,\n ConsumerNotFoundByConsumerId,\n UnknownError\n )",
+ "tags": "List(apiTagScope, apiTagConsumer)"
+ },
+ "addScope": {
+ "partial_function_name_raw": "nameOf(addScope)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumers/CONSUMER_ID/scopes\"",
+ "summary": "\"Create Scope for a Consumer\"",
+ "description": "\"\"\"Create Scope. Grant Role to Consumer.\n |\n |Scopes are used to grant System or Bank level roles to the Consumer (App). (For Account level privileges, see Views)\n |\n |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. \"bank_id\":\"\"\n |\n |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. \"bank_id\":\"my-bank-id\"\n |\n |\"\"\"",
+ "example_request_body": "SwaggerDefinitionsJSON.createScopeJson",
+ "success_response_body": "scopeJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n ConsumerNotFoundById,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementIsBankRole,\n EntitlementIsSystemRole,\n EntitlementAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagScope, apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateScopeAtAnyBank, canCreateScopeAtOneBank))"
+ }
+ },
+ "deleteCustomerAttribute": {
+ "partial_function_name_raw": "nameOf(deleteCustomerAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Customer Attribute\"",
+ "description": "s\"\"\" Delete Customer Attribute\n |\n |$customerAttributeGeneralInfo\n |\n |Delete a Customer Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(\n List(\n canDeleteCustomerAttributeAtOneBank,\n canDeleteCustomerAttributeAtAnyBank\n )\n )"
+ }
+ },
+ "createDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(createDynamicEndpoint)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/dynamic-endpoints\"",
+ "summary": "\"Create Dynamic Endpoint\"",
+ "description": "s\"\"\"Create dynamic endpoints.\n |\n |Create dynamic endpoints with one json format swagger content.\n |\n |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields,\n |please check `Endpoint Mapping` endpoints.\n |\n |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\\n\n |when create MethodRouting for given dynamic endpoint, it will be routed to given url.\n |\n |\"\"\"",
+ "example_request_body": "dynamicEndpointRequestBodyExample",
+ "success_response_body": "dynamicEndpointResponseBodyExample",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEndpointExists,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateDynamicEndpoint))"
+ }
+ },
+ "createBankLevelDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(createBankLevelDynamicEndpoint)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-endpoints\"",
+ "summary": "\"Create Bank Level Dynamic Endpoint\"",
+ "description": "s\"\"\"Create dynamic endpoints.\n |\n |Create dynamic endpoints with one json format swagger content.\n |\n |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields,\n |please check `Endpoint Mapping` endpoints.\n |\n |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\\n\n |when create MethodRouting for given dynamic endpoint, it will be routed to given url.\n |\n |\"\"\"",
+ "example_request_body": "dynamicEndpointRequestBodyExample",
+ "success_response_body": "dynamicEndpointResponseBodyExample",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEndpointExists,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelDynamicEndpoint, canCreateDynamicEndpoint))"
+ }
+ },
+ "updateDynamicEndpointHost": {
+ "partial_function_name_raw": "nameOf(updateDynamicEndpointHost)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host\"",
+ "summary": "\" Update Dynamic Endpoint Host\"",
+ "description": "s\"\"\"Update dynamic endpoint Host.\n |The value can be obp_mock, dynamic_entity, or some service url.\n |\"\"\"",
+ "example_request_body": "dynamicEndpointHostJson400",
+ "success_response_body": "dynamicEndpointHostJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEntityNotFoundByDynamicEntityId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateDynamicEndpoint))"
+ }
+ },
+ "updateBankLevelDynamicEndpointHost": {
+ "partial_function_name_raw": "nameOf(updateBankLevelDynamicEndpointHost)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host\"",
+ "summary": "\" Update Bank Level Dynamic Endpoint Host\"",
+ "description": "s\"\"\"Update Bank Level dynamic endpoint Host.\n |The value can be obp_mock, dynamic_entity, or some service url.\n |\"\"\"",
+ "example_request_body": "dynamicEndpointHostJson400",
+ "success_response_body": "dynamicEndpointHostJson400",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEntityNotFoundByDynamicEntityId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankLevelDynamicEndpoint, canUpdateDynamicEndpoint))"
+ }
+ },
+ "getDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(getDynamicEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID\"",
+ "summary": "\"Get Dynamic Endpoint\"",
+ "description": "s\"\"\"Get a Dynamic Endpoint.\n |\n |\n |Get one DynamicEndpoint,\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "dynamicEndpointResponseBodyExample",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEndpointNotFoundByDynamicEndpointId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicEndpoint))"
+ }
+ },
+ "getDynamicEndpoints": {
+ "partial_function_name_raw": "nameOf(getDynamicEndpoints)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-endpoints\"",
+ "summary": "\" Get Dynamic Endpoints\"",
+ "description": "s\"\"\"\n |\n |Get Dynamic Endpoints.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_endpoints\",\n List(dynamicEndpointResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicEndpoints))"
+ }
+ },
+ "getBankLevelDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID\"",
+ "summary": "\" Get Bank Level Dynamic Endpoint\"",
+ "description": "s\"\"\"Get a Bank Level Dynamic Endpoint.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "dynamicEndpointResponseBodyExample",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n DynamicEndpointNotFoundByDynamicEndpointId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicEndpoint, canGetDynamicEndpoint))"
+ }
+ },
+ "getBankLevelDynamicEndpoints": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicEndpoints)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-endpoints\"",
+ "summary": "\"Get Bank Level Dynamic Endpoints\"",
+ "description": "s\"\"\"\n |\n |Get Bank Level Dynamic Endpoints.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_endpoints\",\n List(dynamicEndpointResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicEndpoints, canGetDynamicEndpoints))"
+ }
+ },
+ "deleteDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(deleteDynamicEndpoint)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID\"",
+ "summary": "\" Delete Dynamic Endpoint\"",
+ "description": "s\"\"\"Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n DynamicEndpointNotFoundByDynamicEndpointId,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteDynamicEndpoint))"
+ }
+ },
+ "deleteBankLevelDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelDynamicEndpoint)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID\"",
+ "summary": "\" Delete Bank Level Dynamic Endpoint\"",
+ "description": "s\"\"\"Delete a Bank Level DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n DynamicEndpointNotFoundByDynamicEndpointId,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelDynamicEndpoint, canDeleteDynamicEndpoint))"
+ }
+ },
+ "getMyDynamicEndpoints": {
+ "partial_function_name_raw": "nameOf(getMyDynamicEndpoints)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/dynamic-endpoints\"",
+ "summary": "\"Get My Dynamic Endpoints\"",
+ "description": "s\"\"\"Get My Dynamic Endpoints.\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"dynamic_endpoints\",\n List(dynamicEndpointResponseBodyExample)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)"
+ },
+ "deleteMyDynamicEndpoint": {
+ "partial_function_name_raw": "nameOf(deleteMyDynamicEndpoint)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/dynamic-endpoints/DYNAMIC_ENDPOINT_ID\"",
+ "summary": "\"Delete My Dynamic Endpoint\"",
+ "description": "s\"\"\"Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n DynamicEndpointNotFoundByDynamicEndpointId,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEndpoint, apiTagApi)"
+ },
+ "createOrUpdateCustomerAttributeAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateCustomerAttributeAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/customer\"",
+ "summary": "\"Create or Update Customer Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Customer Attribute Definition\n |\n |The category field must be one of: ${AttributeCategory.Customer}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "templateAttributeDefinitionJsonV400",
+ "success_response_body": "templateAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomerAttributeDefinitionAtOneBank))"
+ }
+ },
+ "createOrUpdateAccountAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateAccountAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/account\"",
+ "summary": "\"Create or Update Account Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Account Attribute Definition\n |\n |The category field must be ${AttributeCategory.Account}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "accountAttributeDefinitionJsonV400",
+ "success_response_body": "accountAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccountAttributeDefinitionAtOneBank))"
+ }
+ },
+ "createOrUpdateProductAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateProductAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/product\"",
+ "summary": "\"Create or Update Product Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Product Attribute Definition\n |\n |The category field must be ${AttributeCategory.Product}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productAttributeDefinitionJsonV400",
+ "success_response_body": "productAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProductAttributeDefinitionAtOneBank))"
+ }
+ },
+ "createProductAttribute": {
+ "partial_function_name_raw": "nameOf(createProductAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attribute\"",
+ "summary": "\"Create Product Attribute\"",
+ "description": "s\"\"\" Create Product Attribute\n |\n |$productAttributeGeneralInfo\n |\n |Typical product attributes might be:\n |\n |ISIN (for International bonds)\n |VKN (for German bonds)\n |REDCODE (markit short code for credit derivative)\n |LOAN_ID (e.g. used for Anacredit reporting)\n |\n |ISSUE_DATE (When the bond was issued in the market)\n |MATURITY_DATE (End of life time of a product)\n |TRADABLE\n |\n |See [FPML](http://www.fpml.org/) for more examples.\n |\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productAttributeJsonV400",
+ "success_response_body": "productAttributeResponseJsonV400",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProductAttribute))"
+ }
+ },
+ "updateProductAttribute": {
+ "partial_function_name_raw": "nameOf(updateProductAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Update Product Attribute\"",
+ "description": "s\"\"\" Update Product Attribute.\n |\n\n |$productAttributeGeneralInfo\n |\n |Update one Product Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productAttributeJsonV400",
+ "success_response_body": "productAttributeResponseJsonV400",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateProductAttribute))"
+ }
+ },
+ "getProductAttribute": {
+ "partial_function_name_raw": "nameOf(getProductAttribute)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Get Product Attribute\"",
+ "description": "s\"\"\" Get Product Attribute\n |\n |$productAttributeGeneralInfo\n |\n |Get one product attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productAttributeResponseJsonV400",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateProductAttribute))"
+ }
+ },
+ "createProductFee": {
+ "partial_function_name_raw": "nameOf(createProductFee)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/fee\"",
+ "summary": "\"Create Product Fee\"",
+ "description": "s\"\"\"Create Product Fee\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productFeeJsonV400.copy(product_fee_id = None)",
+ "success_response_body": "productFeeResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProductFee))"
+ }
+ },
+ "updateProductFee": {
+ "partial_function_name_raw": "nameOf(updateProductFee)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID\"",
+ "summary": "\"Update Product Fee\"",
+ "description": "s\"\"\" Update Product Fee.\n |\n |Update one Product Fee by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "productFeeJsonV400.copy(product_fee_id = None)",
+ "success_response_body": "productFeeResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateProductFee))"
+ }
+ },
+ "getProductFee": {
+ "partial_function_name_raw": "nameOf(getProductFee)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID\"",
+ "summary": "\"Get Product Fee\"",
+ "description": "s\"\"\" Get Product Fee\n |\n |Get one product fee by its id.\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productFeeResponseJsonV400",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "getProductFees": {
+ "partial_function_name_raw": "nameOf(getProductFees)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/fees\"",
+ "summary": "\"Get Product Fees\"",
+ "description": "s\"\"\"Get Product Fees\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productFeesResponseJsonV400",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "deleteProductFee": {
+ "partial_function_name_raw": "nameOf(deleteProductFee)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID\"",
+ "summary": "\"Delete Product Fee\"",
+ "description": "s\"\"\"Delete Product Fee\n |\n |Delete one product fee by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteProductFee))"
+ }
+ },
+ "createOrUpdateBankAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateBankAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/bank\"",
+ "summary": "\"Create or Update Bank Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Bank Attribute Definition\n |\n |The category field must be ${AttributeCategory.Bank}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "bankAttributeDefinitionJsonV400",
+ "success_response_body": "bankAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankAttributeDefinitionAtOneBank))"
+ }
+ },
+ "createBankAttribute": {
+ "partial_function_name_raw": "nameOf(createBankAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/attribute\"",
+ "summary": "\"Create Bank Attribute\"",
+ "description": "s\"\"\" Create Bank Attribute\n |\n |Typical product attributes might be:\n |\n |ISIN (for International bonds)\n |VKN (for German bonds)\n |REDCODE (markit short code for credit derivative)\n |LOAN_ID (e.g. used for Anacredit reporting)\n |\n |ISSUE_DATE (When the bond was issued in the market)\n |MATURITY_DATE (End of life time of a product)\n |TRADABLE\n |\n |See [FPML](http://www.fpml.org/) for more examples.\n |\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "bankAttributeJsonV400",
+ "success_response_body": "bankAttributeResponseJsonV400",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankAttribute))"
+ }
+ },
+ "getBankAttributes": {
+ "partial_function_name_raw": "nameOf(getBankAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attributes\"",
+ "summary": "\"Get Bank Attributes\"",
+ "description": "s\"\"\" Get Bank Attributes\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankAttributesResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankAttribute))"
+ }
+ },
+ "getBankAttribute": {
+ "partial_function_name_raw": "nameOf(getBankAttribute)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID\"",
+ "summary": "\"Get Bank Attribute By BANK_ATTRIBUTE_ID\"",
+ "description": "s\"\"\" Get Bank Attribute By BANK_ATTRIBUTE_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankAttributeResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankAttribute))"
+ }
+ },
+ "updateBankAttribute": {
+ "partial_function_name_raw": "nameOf(updateBankAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID\"",
+ "summary": "\"Update Bank Attribute\"",
+ "description": "s\"\"\" Update Bank Attribute.\n |\n |Update one Bak Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "bankAttributeJsonV400",
+ "success_response_body": "bankAttributeDefinitionJsonV400",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)"
+ },
+ "deleteBankAttribute": {
+ "partial_function_name_raw": "nameOf(deleteBankAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Bank Attribute\"",
+ "description": "s\"\"\" Delete Bank Attribute\n |\n |Delete a Bank Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagBank, apiTagBankAttribute, apiTagAttribute)"
+ },
+ "createOrUpdateTransactionAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateTransactionAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/transaction\"",
+ "summary": "\"Create or Update Transaction Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Transaction Attribute Definition\n |\n |The category field must be ${AttributeCategory.Transaction}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "transactionAttributeDefinitionJsonV400",
+ "success_response_body": "transactionAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateTransactionAttributeDefinitionAtOneBank))"
+ }
+ },
+ "createOrUpdateCardAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(createOrUpdateCardAttributeDefinition)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/card\"",
+ "summary": "\"Create or Update Card Attribute Definition\"",
+ "description": "s\"\"\" Create or Update Card Attribute Definition\n |\n |The category field must be ${AttributeCategory.Card}\n |\n |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "cardAttributeDefinitionJsonV400",
+ "success_response_body": "cardAttributeDefinitionResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCard, apiTagCardAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCardAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteTransactionAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteTransactionAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction\"",
+ "summary": "\"Delete Transaction Attribute Definition\"",
+ "description": "s\"\"\" Delete Transaction Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteTransactionAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteCustomerAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteCustomerAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/customer\"",
+ "summary": "\"Delete Customer Attribute Definition\"",
+ "description": "s\"\"\" Delete Customer Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCustomerAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteAccountAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteAccountAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/account\"",
+ "summary": "\"Delete Account Attribute Definition\"",
+ "description": "s\"\"\" Delete Account Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAccountAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteProductAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteProductAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/product\"",
+ "summary": "\"Delete Product Attribute Definition\"",
+ "description": "s\"\"\" Delete Product Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteProductAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteCardAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(deleteCardAttributeDefinition)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/card\"",
+ "summary": "\"Delete Card Attribute Definition\"",
+ "description": "s\"\"\" Delete Card Attribute Definition by ATTRIBUTE_DEFINITION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCard, apiTagCardAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCardAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getProductAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getProductAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/product\"",
+ "summary": "\"Get Product Attribute Definition\"",
+ "description": "s\"\"\" Get Product Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct, apiTagProductAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetProductAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getCustomerAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getCustomerAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/customer\"",
+ "summary": "\"Get Customer Attribute Definition\"",
+ "description": "s\"\"\" Get Customer Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getAccountAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getAccountAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/account\"",
+ "summary": "\"Get Account Attribute Definition\"",
+ "description": "s\"\"\" Get Account Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getTransactionAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getTransactionAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/transaction\"",
+ "summary": "\"Get Transaction Attribute Definition\"",
+ "description": "s\"\"\" Get Transaction Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionAttributeDefinitionAtOneBank))"
+ }
+ },
+ "getCardAttributeDefinition": {
+ "partial_function_name_raw": "nameOf(getCardAttributeDefinition)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/attribute-definitions/card\"",
+ "summary": "\"Get Card Attribute Definition\"",
+ "description": "s\"\"\" Get Card Attribute Definition\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "cardAttributeDefinitionsResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCard, apiTagCardAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCardAttributeDefinitionAtOneBank))"
+ }
+ },
+ "deleteUserCustomerLink": {
+ "partial_function_name_raw": "nameOf(deleteUserCustomerLink)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/user_customer_links/USER_CUSTOMER_LINK_ID\"",
+ "summary": "\"Delete User Customer Link\"",
+ "description": "s\"\"\" Delete User Customer Link by USER_CUSTOMER_LINK_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteUserCustomerLink))"
+ }
+ },
+ "getUserCustomerLinksByUserId": {
+ "partial_function_name_raw": "nameOf(getUserCustomerLinksByUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/user_customer_links/users/USER_ID\"",
+ "summary": "\"Get User Customer Links by User\"",
+ "description": "s\"\"\" Get User Customer Links by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userCustomerLinksJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserCustomerLink))"
+ }
+ },
+ "createUserCustomerLinks": {
+ "partial_function_name_raw": "\"createUserCustomerLinks\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/user_customer_links\"",
+ "summary": "\"Create User Customer Link\"",
+ "description": "s\"\"\"Link a User to a Customer\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "createUserCustomerLinkJson",
+ "success_response_body": "userCustomerLinkJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidBankIdFormat,\n $BankNotFound,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n CustomerAlreadyExistsForUser,\n CreateUserCustomerLinksError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateUserCustomerLinkAtAnyBank, canCreateUserCustomerLink))"
+ }
+ },
+ "getUserCustomerLinksByCustomerId": {
+ "partial_function_name_raw": "nameOf(getUserCustomerLinksByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/user_customer_links/customers/CUSTOMER_ID\"",
+ "summary": "\"Get User Customer Links by Customer\"",
+ "description": "s\"\"\" Get User Customer Links by CUSTOMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userCustomerLinksJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserCustomerLink))"
+ }
+ },
+ "getCorrelatedUsersInfoByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCorrelatedUsersInfoByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/correlated-users\"",
+ "summary": "\"Get Correlated User Info by Customer\"",
+ "description": "s\"\"\"Get Correlated User Info by CUSTOMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAndUsersWithAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCorrelatedUsersInfoAtAnyBank, canGetCorrelatedUsersInfo))"
+ }
+ },
+ "getMyCorrelatedEntities": {
+ "partial_function_name_raw": "nameOf(getMyCorrelatedEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/correlated-entities\"",
+ "summary": "\"Get Correlated Entities for the current User\"",
+ "description": "s\"\"\"Correlated Entities are users and customers linked to the currently authenticated user via User-Customer-Links\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "correlatedUsersResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)"
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "nameOf(createCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"\n |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |\n |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postCustomerJsonV310",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getAccountsMinimalByCustomerId": {
+ "partial_function_name_raw": "nameOf(getAccountsMinimalByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers/CUSTOMER_ID/accounts-minimal\"",
+ "summary": "\"Get Accounts Minimal for a Customer\"",
+ "description": "s\"\"\"Get Accounts Minimal by CUSTOMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountsMinimalJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n CustomerNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountsMinimalForCustomerAtOneBank, canGetAccountsMinimalForCustomerAtAnyBank))"
+ }
+ },
+ "deleteTransactionCascade": {
+ "partial_function_name_raw": "nameOf(deleteTransactionCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID\"",
+ "summary": "\"Delete Transaction Cascade\"",
+ "description": "s\"\"\"Delete a Transaction Cascade specified by TRANSACTION_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteTransactionCascade))"
+ }
+ },
+ "deleteAccountCascade": {
+ "partial_function_name_raw": "nameOf(deleteAccountCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Delete Account Cascade\"",
+ "description": "s\"\"\"Delete an Account Cascade specified by ACCOUNT_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAccountCascade))"
+ }
+ },
+ "deleteBankCascade": {
+ "partial_function_name_raw": "nameOf(deleteBankCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/cascading/banks/BANK_ID\"",
+ "summary": "\"Delete Bank Cascade\"",
+ "description": "s\"\"\"Delete a Bank Cascade specified by BANK_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankCascade))"
+ }
+ },
+ "deleteProductCascade": {
+ "partial_function_name_raw": "nameOf(deleteProductCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/cascading/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Delete Product Cascade\"",
+ "description": "s\"\"\"Delete a Product Cascade specified by PRODUCT_CODE.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteProductCascade))"
+ }
+ },
+ "deleteCustomerCascade": {
+ "partial_function_name_raw": "nameOf(deleteCustomerCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/cascading/banks/BANK_ID/customers/CUSTOMER_ID\"",
+ "summary": "\"Delete Customer Cascade\"",
+ "description": "s\"\"\"Delete a Customer Cascade specified by CUSTOMER_ID.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCustomerCascade))"
+ }
+ },
+ "createCounterparty": {
+ "partial_function_name_raw": "\"createCounterparty\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Create Counterparty (Explicit)\"",
+ "description": "s\"\"\"This endpoint creates an (Explicit) Counterparty for an Account.\n |\n |For an introduction to Counterparties in OBP see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postCounterpartyJson400",
+ "success_response_body": "counterpartyWithMetadataJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n InvalidISOCurrencyCode,\n ViewNotFound,\n CounterpartyAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ },
+ "deleteExplicitCounterparty": {
+ "partial_function_name_raw": "nameOf(deleteExplicitCounterparty)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID\"",
+ "summary": "\"Delete Counterparty (Explicit)\"",
+ "description": "s\"\"\"This endpoint deletes the Counterparty on the Account / View specified by the COUNTERPARTY_ID.\n |It also deletes any related Counterparty Metadata.\n |\n |The User calling this endpoint must have access to the View specified in the URL and that View must have the permission `can_delete_counterparty`.\n |\n |For a general introduction to Counterparties in OBP see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n | |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)"
+ },
+ "deleteCounterpartyForAnyAccount": {
+ "partial_function_name_raw": "nameOf(deleteCounterpartyForAnyAccount)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID\"",
+ "summary": "\"Delete Counterparty for any account (Explicit)\"",
+ "description": "s\"\"\"This is a management endpoint that enables the deletion of any specified Counterparty along with any related Metadata of that Counterparty.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankAccountNotFound,\n $BankNotFound,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCounterparty, canDeleteCounterpartyAtAnyBank))"
+ }
+ },
+ "createCounterpartyForAnyAccount": {
+ "partial_function_name_raw": "\"createCounterpartyForAnyAccount\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Create Counterparty for any account (Explicit)\"",
+ "description": "s\"\"\"This is a management endpoint that allows the creation of a Counterparty on any Account.\n |\n |For an introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postCounterpartyJson400",
+ "success_response_body": "counterpartyWithMetadataJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n $BankNotFound,\n $BankAccountNotFound,\n AccountNotFound,\n InvalidJsonFormat,\n InvalidISOCurrencyCode,\n ViewNotFound,\n CounterpartyAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCounterparty, canCreateCounterpartyAtAnyBank))"
+ }
+ },
+ "getExplicitCounterpartiesForAccount": {
+ "partial_function_name_raw": "\"getExplicitCounterpartiesForAccount\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Get Counterparties (Explicit)\"",
+ "description": "s\"\"\"Get the Counterparties that have been explicitly created on the specified Account / View.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartiesJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount)"
+ },
+ "getCounterpartiesForAnyAccount": {
+ "partial_function_name_raw": "nameOf(getCounterpartiesForAnyAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties\"",
+ "summary": "\"Get Counterparties for any account (Explicit)\"",
+ "description": "s\"\"\"This is a management endpoint that gets the Counterparties that have been explicitly created for an Account / View.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartiesJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCounterparties, canGetCounterpartiesAtAnyBank))"
+ }
+ },
+ "getExplicitCounterpartyById": {
+ "partial_function_name_raw": "\"getExplicitCounterpartyById\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID\"",
+ "summary": "\"Get Counterparty by Id (Explicit)\"",
+ "description": "s\"\"\"This endpoint returns a single Counterparty on an Account View specified by its COUNTERPARTY_ID:\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyWithMetadataJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(\n apiTagCounterparty,\n apiTagPSD2PIS,\n apiTagPsd2,\n apiTagCounterpartyMetaData\n )"
+ },
+ "getCounterpartyByNameForAnyAccount": {
+ "partial_function_name_raw": "nameOf(getCounterpartyByNameForAnyAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparty-names/COUNTERPARTY_NAME\"",
+ "summary": "\"Get Counterparty by name for any account (Explicit) \"",
+ "description": "s\"\"\"This is a management endpoint that allows the retrieval of any Counterparty on an Account / View by its Name.\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyWithMetadataJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty))"
+ }
+ },
+ "getCounterpartyByIdForAnyAccount": {
+ "partial_function_name_raw": "nameOf(getCounterpartyByIdForAnyAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID\"",
+ "summary": "\"Get Counterparty by Id for any account (Explicit)\"",
+ "description": "s\"\"\"This is a management endpoint that gets information about any single explicitly created Counterparty on an Account / View specified by its COUNTERPARTY_ID\",\n |\n |For a general introduction to Counterparties in OBP, see ${Glossary\n .getGlossaryItemLink(\"Counterparties\")}\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyWithMetadataJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCounterparty, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty))"
+ }
+ },
+ "addConsentUser": {
+ "partial_function_name_raw": "nameOf(addConsentUser)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/consents/CONSENT_ID/user-update-request\"",
+ "summary": "\"Add User to a Consent\"",
+ "description": "s\"\"\"\n |\n |\n |This endpoint is used to add the User of Consent.\n |\n |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted\n .mkString(\", \")}.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PutConsentUserJsonV400(user_id = \"ed7a7c01-db37-45cc-ba12-0ae8891c195c\")",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt =\n \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"AUTHORISED\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n $BankNotFound,\n ConsentUserAlreadyAdded,\n InvalidJsonFormat,\n ConsentNotFound,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: Nil"
+ },
+ "updateConsentStatus": {
+ "partial_function_name_raw": "nameOf(updateConsentStatus)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/consents/CONSENT_ID\"",
+ "summary": "\"Update Consent Status\"",
+ "description": "s\"\"\"\n |\n |\n |This endpoint is used to update the Status of Consent.\n |\n |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted\n .mkString(\", \")}.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PutConsentStatusJsonV400(status = \"AUTHORISED\")",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt =\n \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"AUTHORISED\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: Nil"
+ },
+ "getConsents": {
+ "partial_function_name_raw": "nameOf(getConsents)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/consents\"",
+ "summary": "\"Get Consents\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents that the current User created.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getConsentInfosByBank": {
+ "partial_function_name_raw": "nameOf(getConsentInfosByBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/consent-infos\"",
+ "summary": "\"Get My Consents Info At Bank\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents that the current User created at bank.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentInfosJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getConsentInfos": {
+ "partial_function_name_raw": "nameOf(getConsentInfos)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/consent-infos\"",
+ "summary": "\"Get My Consents Info\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents that the current User created.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentInfosJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getMyPersonalUserAttributes": {
+ "partial_function_name_raw": "nameOf(getMyPersonalUserAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/user/attributes\"",
+ "summary": "\"Get My Personal User Attributes\"",
+ "description": "s\"\"\"Get My Personal User Attributes.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagUser)"
+ },
+ "getUserWithAttributes": {
+ "partial_function_name_raw": "nameOf(getUserWithAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/attributes\"",
+ "summary": "\"Get User with Attributes by USER_ID\"",
+ "description": "s\"\"\"Get User Attributes for the user defined via USER_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userWithAttributesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(canGetUsersWithAttributes :: Nil)"
+ }
+ },
+ "createMyPersonalUserAttribute": {
+ "partial_function_name_raw": "nameOf(createMyPersonalUserAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/user/attributes\"",
+ "summary": "\"Create My Personal User Attribute\"",
+ "description": "s\"\"\" Create My Personal User Attribute\n |\n |The `type` field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "userAttributeJsonV400",
+ "success_response_body": "userAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "updateMyPersonalUserAttribute": {
+ "partial_function_name_raw": "nameOf(updateMyPersonalUserAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/my/user/attributes/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Update My Personal User Attribute\"",
+ "description": "s\"\"\"Update My Personal User Attribute for current user by USER_ATTRIBUTE_ID\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "userAttributeJsonV400",
+ "success_response_body": "userAttributeResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "getScannedApiVersions": {
+ "partial_function_name_raw": "nameOf(getScannedApiVersions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api/versions\"",
+ "summary": "\"Get scanned API Versions\"",
+ "description": "s\"\"\"Get all the scanned API Versions.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"scanned_api_versions\",\n List(Extraction.decompose(ApiVersion.v3_1_0))\n )",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagDocumentation, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(Nil)"
+ }
+ },
+ "createMyApiCollection": {
+ "partial_function_name_raw": "nameOf(createMyApiCollection)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/api-collections\"",
+ "summary": "\"Create My Api Collection\"",
+ "description": "s\"\"\"Create Api Collection for logged in user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "postApiCollectionJson400",
+ "success_response_body": "apiCollectionJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollectionByName": {
+ "partial_function_name_raw": "nameOf(getMyApiCollectionByName)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collections/name/API_COLLECTION_NAME\"",
+ "summary": "\"Get My Api Collection By Name\"",
+ "description": "s\"\"\"Get Api Collection By API_COLLECTION_NAME.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollectionById": {
+ "partial_function_name_raw": "nameOf(getMyApiCollectionById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_ID\"",
+ "summary": "\"Get My Api Collection By Id\"",
+ "description": "s\"\"\"Get Api Collection By API_COLLECTION_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getSharableApiCollectionById": {
+ "partial_function_name_raw": "nameOf(getSharableApiCollectionById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api-collections/sharable/API_COLLECTION_ID\"",
+ "summary": "\"Get Sharable Api Collection By Id\"",
+ "description": "s\"\"\"Get Sharable Api Collection By Id.\n |${userAuthenticationMessage(false)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionJson400",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getApiCollectionsForUser": {
+ "partial_function_name_raw": "nameOf(getApiCollectionsForUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/api-collections\"",
+ "summary": "\"Get Api Collections for User\"",
+ "description": "s\"\"\"Get Api Collections for User.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionsJson400",
+ "error_response_bodies": "List(\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)",
+ "extra_named_args": {
+ "roles": "Some(canGetApiCollectionsForUser :: Nil)"
+ }
+ },
+ "getFeaturedApiCollections": {
+ "partial_function_name_raw": "nameOf(getFeaturedApiCollections)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api-collections/featured\"",
+ "summary": "\"Get Featured Api Collections\"",
+ "description": "s\"\"\"Get Featured Api Collections.\n |\n |${userAuthenticationMessage(false)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionsJson400",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollections": {
+ "partial_function_name_raw": "nameOf(getMyApiCollections)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collections\"",
+ "summary": "\"Get My Api Collections\"",
+ "description": "s\"\"\"Get all the apiCollections for logged in user.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionsJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "deleteMyApiCollection": {
+ "partial_function_name_raw": "nameOf(deleteMyApiCollection)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_ID\"",
+ "summary": "\"Delete My Api Collection\"",
+ "description": "s\"\"\"Delete Api Collection By API_COLLECTION_ID\n |\n |${Glossary.getGlossaryItem(\"API Collections\")}\n |\n |${userAuthenticationMessage(true)}\n |\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "createMyApiCollectionEndpoint": {
+ "partial_function_name_raw": "nameOf(createMyApiCollectionEndpoint)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints\"",
+ "summary": "\"Create My Api Collection Endpoint\"",
+ "description": "s\"\"\"Create Api Collection Endpoint.\n |\n |${Glossary.getGlossaryItem(\"API Collections\")}\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postApiCollectionEndpointJson400",
+ "success_response_body": "apiCollectionEndpointJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "createMyApiCollectionEndpointById": {
+ "partial_function_name_raw": "nameOf(createMyApiCollectionEndpointById)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints\"",
+ "summary": "\"Create My Api Collection Endpoint By Id\"",
+ "description": "s\"\"\"Create Api Collection Endpoint By Id.\n |\n |${Glossary.getGlossaryItem(\"API Collections\")}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postApiCollectionEndpointJson400",
+ "success_response_body": "apiCollectionEndpointJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollectionEndpoint": {
+ "partial_function_name_raw": "nameOf(getMyApiCollectionEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID\"",
+ "summary": "\"Get My Api Collection Endpoint\"",
+ "description": "s\"\"\"Get Api Collection Endpoint By API_COLLECTION_NAME and OPERATION_ID.\n |\n |${userAuthenticationMessage(false)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionEndpointJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getApiCollectionEndpoints": {
+ "partial_function_name_raw": "nameOf(getApiCollectionEndpoints)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api-collections/API_COLLECTION_ID/api-collection-endpoints\"",
+ "summary": "\"Get Api Collection Endpoints\"",
+ "description": "s\"\"\"Get Api Collection Endpoints By API_COLLECTION_ID.\n |\n |${userAuthenticationMessage(false)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionEndpointsJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollectionEndpoints": {
+ "partial_function_name_raw": "nameOf(getMyApiCollectionEndpoints)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints\"",
+ "summary": "\"Get My Api Collection Endpoints\"",
+ "description": "s\"\"\"Get Api Collection Endpoints By API_COLLECTION_NAME.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionEndpointsJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getMyApiCollectionEndpointsById": {
+ "partial_function_name_raw": "nameOf(getMyApiCollectionEndpointsById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints\"",
+ "summary": "\"Get My Api Collection Endpoints By Id\"",
+ "description": "s\"\"\"Get Api Collection Endpoints By API_COLLECTION_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionEndpointsJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "deleteMyApiCollectionEndpoint": {
+ "partial_function_name_raw": "nameOf(deleteMyApiCollectionEndpoint)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID\"",
+ "summary": "\"Delete My Api Collection Endpoint\"",
+ "description": "s\"\"\"${Glossary.getGlossaryItem(\"API Collections\")}\n |\n |\n |Delete Api Collection Endpoint By OPERATION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "deleteMyApiCollectionEndpointByOperationId": {
+ "partial_function_name_raw": "nameOf(deleteMyApiCollectionEndpointByOperationId)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints/OPERATION_ID\"",
+ "summary": "\"Delete My Api Collection Endpoint By Id\"",
+ "description": "s\"\"\"${Glossary.getGlossaryItem(\"API Collections\")}\n |\n |Delete Api Collection Endpoint By OPERATION_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "deleteMyApiCollectionEndpointById": {
+ "partial_function_name_raw": "nameOf(deleteMyApiCollectionEndpointById)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoint-ids/API_COLLECTION_ENDPOINT_ID\"",
+ "summary": "\"Delete My Api Collection Endpoint By Id\"",
+ "description": "s\"\"\"${Glossary.getGlossaryItem(\"API Collections\")}\n |Delete Api Collection Endpoint\n |Delete Api Collection Endpoint By Id\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "createJsonSchemaValidation": {
+ "partial_function_name_raw": "nameOf(createJsonSchemaValidation)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/json-schema-validations/OPERATION_ID\"",
+ "summary": "\"Create a JSON Schema Validation\"",
+ "description": "s\"\"\"Create a JSON Schema Validation.\n |\n |Introduction:\n |${Glossary.getGlossaryItemSimple(\"JSON Schema Validation\")}\n |\n |To use this endpoint, please supply a valid json-schema in the request body.\n |\n |Note: It might take a few minutes for the newly created JSON Schema to take effect!\n |\"\"\"",
+ "example_request_body": "postOrPutJsonSchemaV400",
+ "success_response_body": "responseJsonSchema",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateJsonSchemaValidation))"
+ }
+ },
+ "updateJsonSchemaValidation": {
+ "partial_function_name_raw": "nameOf(updateJsonSchemaValidation)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/json-schema-validations/OPERATION_ID\"",
+ "summary": "\"Update a JSON Schema Validation\"",
+ "description": "s\"\"\"Update a JSON Schema Validation.\n |\n |Introduction:\n |${Glossary.getGlossaryItemSimple(\"JSON Schema Validation\")}\n |\n |To use this endpoint, please supply a valid json-schema in the request body.\n |\n |\"\"\"",
+ "example_request_body": "postOrPutJsonSchemaV400",
+ "success_response_body": "responseJsonSchema",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateJsonSchemaValidation))"
+ }
+ },
+ "deleteJsonSchemaValidation": {
+ "partial_function_name_raw": "nameOf(deleteJsonSchemaValidation)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/json-schema-validations/OPERATION_ID\"",
+ "summary": "\"Delete a JSON Schema Validation\"",
+ "description": "s\"\"\"Delete a JSON Schema Validation by operation_id.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteJsonSchemaValidation))"
+ }
+ },
+ "getJsonSchemaValidation": {
+ "partial_function_name_raw": "nameOf(getJsonSchemaValidation)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/json-schema-validations/OPERATION_ID\"",
+ "summary": "\"Get a JSON Schema Validation\"",
+ "description": "s\"\"\"Get a JSON Schema Validation by operation_id.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "responseJsonSchema",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetJsonSchemaValidation))"
+ }
+ },
+ "getAllJsonSchemaValidations": {
+ "partial_function_name_raw": "nameOf(getAllJsonSchemaValidations)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/json-schema-validations\"",
+ "summary": "\"Get all JSON Schema Validations\"",
+ "description": "s\"\"\"Get all JSON Schema Validations.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"json_schema_validations\", responseJsonSchema :: Nil)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetJsonSchemaValidation))"
+ }
+ },
+ "getAllJsonSchemaValidationsPublic": {
+ "partial_function_name_raw": "nameOf(getAllJsonSchemaValidationsPublic)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/endpoints/json-schema-validations\"",
+ "summary": "\"Get all JSON Schema Validations - public\"",
+ "description": "s\"\"\"Get all JSON Schema Validations - public.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"json_schema_validations\", responseJsonSchema :: Nil)",
+ "error_response_bodies": "(if (jsonSchemaValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil)\n ::: List(\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagJsonSchemaValidation)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "createAuthenticationTypeValidation": {
+ "partial_function_name_raw": "nameOf(createAuthenticationTypeValidation)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/authentication-type-validations/OPERATION_ID\"",
+ "summary": "\"Create an Authentication Type Validation\"",
+ "description": "s\"\"\"Create an Authentication Type Validation.\n |\n |Please supply allowed authentication types.\n |\"\"\"",
+ "example_request_body": "allowedAuthTypes",
+ "success_response_body": "JsonAuthTypeValidation(\"OBPv4.0.0-updateXxx\", allowedAuthTypes)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAuthenticationTypeValidation))"
+ }
+ },
+ "updateAuthenticationTypeValidation": {
+ "partial_function_name_raw": "nameOf(updateAuthenticationTypeValidation)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/authentication-type-validations/OPERATION_ID\"",
+ "summary": "\"Update an Authentication Type Validation\"",
+ "description": "s\"\"\"Update an Authentication Type Validation.\n |\n |Please supply allowed authentication types.\n |\"\"\"",
+ "example_request_body": "allowedAuthTypes",
+ "success_response_body": "JsonAuthTypeValidation(\"OBPv4.0.0-updateXxx\", allowedAuthTypes)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAuthenticationTypeValidation))"
+ }
+ },
+ "deleteAuthenticationTypeValidation": {
+ "partial_function_name_raw": "nameOf(deleteAuthenticationTypeValidation)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/authentication-type-validations/OPERATION_ID\"",
+ "summary": "\"Delete an Authentication Type Validation\"",
+ "description": "s\"\"\"Delete an Authentication Type Validation by operation_id.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAuthenticationValidation))"
+ }
+ },
+ "getAuthenticationTypeValidation": {
+ "partial_function_name_raw": "nameOf(getAuthenticationTypeValidation)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/authentication-type-validations/OPERATION_ID\"",
+ "summary": "\"Get an Authentication Type Validation\"",
+ "description": "s\"\"\"Get an Authentication Type Validation by operation_id.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JsonAuthTypeValidation(\"OBPv4.0.0-updateXxx\", allowedAuthTypes)",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAuthenticationTypeValidation))"
+ }
+ },
+ "getAllAuthenticationTypeValidations": {
+ "partial_function_name_raw": "nameOf(getAllAuthenticationTypeValidations)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/authentication-type-validations\"",
+ "summary": "\"Get all Authentication Type Validations\"",
+ "description": "s\"\"\"Get all Authentication Type Validations.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"authentication_types_validations\",\n List(JsonAuthTypeValidation(\"OBPv4.0.0-updateXxx\", allowedAuthTypes))\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAuthenticationTypeValidation))"
+ }
+ },
+ "getAllAuthenticationTypeValidationsPublic": {
+ "partial_function_name_raw": "nameOf(getAllAuthenticationTypeValidationsPublic)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/endpoints/authentication-type-validations\"",
+ "summary": "\"Get all Authentication Type Validations - public\"",
+ "description": "s\"\"\"Get all Authentication Type Validations - public.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"authentication_types_validations\",\n List(JsonAuthTypeValidation(\"OBPv4.0.0-updateXxx\", allowedAuthTypes))\n )",
+ "error_response_bodies": "(if (authenticationTypeValidationRequiresRole) List($AuthenticatedUserIsRequired)\n else Nil)\n ::: List(\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAuthenticationTypeValidation)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "createConnectorMethod": {
+ "partial_function_name_raw": "nameOf(createConnectorMethod)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/connector-methods\"",
+ "summary": "\"Create Connector Method\"",
+ "description": "s\"\"\"Create an internal connector.\n |\n |The method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonScalaConnectorMethod.copy(connectorMethodId = None)",
+ "success_response_body": "jsonScalaConnectorMethod",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConnectorMethod)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateConnectorMethod))"
+ }
+ },
+ "updateConnectorMethod": {
+ "partial_function_name_raw": "nameOf(updateConnectorMethod)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/connector-methods/CONNECTOR_METHOD_ID\"",
+ "summary": "\"Update Connector Method\"",
+ "description": "s\"\"\"Update an internal connector.\n |\n |The method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonScalaConnectorMethodMethodBody",
+ "success_response_body": "jsonScalaConnectorMethod",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConnectorMethod)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConnectorMethod))"
+ }
+ },
+ "getConnectorMethod": {
+ "partial_function_name_raw": "nameOf(getConnectorMethod)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/connector-methods/CONNECTOR_METHOD_ID\"",
+ "summary": "\"Get Connector Method by Id\"",
+ "description": "s\"\"\"Get an internal connector by CONNECTOR_METHOD_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "jsonScalaConnectorMethod",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConnectorMethod)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConnectorMethod))"
+ }
+ },
+ "getAllConnectorMethods": {
+ "partial_function_name_raw": "nameOf(getAllConnectorMethods)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/connector-methods\"",
+ "summary": "\"Get all Connector Methods\"",
+ "description": "s\"\"\"Get all Connector Methods.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"connectors_methods\", jsonScalaConnectorMethod :: Nil)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConnectorMethod)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllConnectorMethods))"
+ }
+ },
+ "createDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(createDynamicResourceDoc)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/dynamic-resource-docs\"",
+ "summary": "\"Create Dynamic Resource Doc\"",
+ "description": "s\"\"\"Create a Dynamic Resource Doc.\n |\n |The connector_method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonDynamicResourceDoc.copy(dynamicResourceDocId = None)",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateDynamicResourceDoc))"
+ }
+ },
+ "updateDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(updateDynamicResourceDoc)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Update Dynamic Resource Doc\"",
+ "description": "s\"\"\"Update a Dynamic Resource Doc.\n |\n |The connector_method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonDynamicResourceDoc.copy(dynamicResourceDocId = None)",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateDynamicResourceDoc))"
+ }
+ },
+ "deleteDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(deleteDynamicResourceDoc)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Delete Dynamic Resource Doc\"",
+ "description": "s\"\"\"Delete a Dynamic Resource Doc.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteDynamicResourceDoc))"
+ }
+ },
+ "getDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(getDynamicResourceDoc)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Get Dynamic Resource Doc by Id\"",
+ "description": "s\"\"\"Get a Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicResourceDoc))"
+ }
+ },
+ "getAllDynamicResourceDocs": {
+ "partial_function_name_raw": "nameOf(getAllDynamicResourceDocs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-resource-docs\"",
+ "summary": "\"Get all Dynamic Resource Docs\"",
+ "description": "s\"\"\"Get all Dynamic Resource Docs.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"dynamic-resource-docs\", jsonDynamicResourceDoc :: Nil)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllDynamicResourceDocs))"
+ }
+ },
+ "createBankLevelDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(createBankLevelDynamicResourceDoc)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-resource-docs\"",
+ "summary": "\"Create Bank Level Dynamic Resource Doc\"",
+ "description": "s\"\"\"Create a Bank Level Dynamic Resource Doc.\n |\n |The connector_method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonDynamicResourceDoc.copy(dynamicResourceDocId = None)",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelDynamicResourceDoc))"
+ }
+ },
+ "updateBankLevelDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(updateBankLevelDynamicResourceDoc)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Update Bank Level Dynamic Resource Doc\"",
+ "description": "s\"\"\"Update a Bank Level Dynamic Resource Doc.\n |\n |The connector_method_body is URL-encoded format String\n |\"\"\"",
+ "example_request_body": "jsonDynamicResourceDoc.copy(dynamicResourceDocId = None)",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankLevelDynamicResourceDoc))"
+ }
+ },
+ "deleteBankLevelDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelDynamicResourceDoc)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Delete Bank Level Dynamic Resource Doc\"",
+ "description": "s\"\"\"Delete a Bank Level Dynamic Resource Doc.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelDynamicResourceDoc))"
+ }
+ },
+ "getBankLevelDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicResourceDoc)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID\"",
+ "summary": "\"Get Bank Level Dynamic Resource Doc by Id\"",
+ "description": "s\"\"\"Get a Bank Level Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "jsonDynamicResourceDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicResourceDoc))"
+ }
+ },
+ "getAllBankLevelDynamicResourceDocs": {
+ "partial_function_name_raw": "nameOf(getAllBankLevelDynamicResourceDocs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-resource-docs\"",
+ "summary": "\"Get all Bank Level Dynamic Resource Docs\"",
+ "description": "s\"\"\"Get all Bank Level Dynamic Resource Docs.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"dynamic-resource-docs\", jsonDynamicResourceDoc :: Nil)",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllBankLevelDynamicResourceDocs))"
+ }
+ },
+ "buildDynamicEndpointTemplate": {
+ "partial_function_name_raw": "nameOf(buildDynamicEndpointTemplate)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/dynamic-resource-docs/endpoint-code\"",
+ "summary": "\"Create Dynamic Resource Doc endpoint code\"",
+ "description": "s\"\"\"Create a Dynamic Resource Doc endpoint code.\n |\n |copy the response and past to ${nameOf(\n PractiseEndpoint\n )}, So you can have the benefits of\n |auto compilation and debug\n |\"\"\"",
+ "example_request_body": "jsonResourceDocFragment",
+ "success_response_body": "jsonCodeTemplateJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "createDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(createDynamicMessageDoc)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/dynamic-message-docs\"",
+ "summary": "\"Create Dynamic Message Doc\"",
+ "description": "s\"\"\"Create a Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "jsonDynamicMessageDoc.copy(dynamicMessageDocId = None)",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateDynamicMessageDoc))"
+ }
+ },
+ "createBankLevelDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(createBankLevelDynamicMessageDoc)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-message-docs\"",
+ "summary": "\"Create Bank Level Dynamic Message Doc\"",
+ "description": "s\"\"\"Create a Bank Level Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "jsonDynamicMessageDoc.copy(dynamicMessageDocId = None)",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelDynamicMessageDoc))"
+ }
+ },
+ "updateDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(updateDynamicMessageDoc)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Update Dynamic Message Doc\"",
+ "description": "s\"\"\"Update a Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "jsonDynamicMessageDoc.copy(dynamicMessageDocId = None)",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateDynamicMessageDoc))"
+ }
+ },
+ "getDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(getDynamicMessageDoc)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Get Dynamic Message Doc\"",
+ "description": "s\"\"\"Get a Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicMessageDoc))"
+ }
+ },
+ "getAllDynamicMessageDocs": {
+ "partial_function_name_raw": "nameOf(getAllDynamicMessageDocs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-message-docs\"",
+ "summary": "\"Get all Dynamic Message Docs\"",
+ "description": "s\"\"\"Get all Dynamic Message Docs.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"dynamic-message-docs\", jsonDynamicMessageDoc :: Nil)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllDynamicMessageDocs))"
+ }
+ },
+ "deleteDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(deleteDynamicMessageDoc)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Delete Dynamic Message Doc\"",
+ "description": "s\"\"\"Delete a Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteDynamicMessageDoc))"
+ }
+ },
+ "updateBankLevelDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(updateBankLevelDynamicMessageDoc)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Update Bank Level Dynamic Message Doc\"",
+ "description": "s\"\"\"Update a Bank Level Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "jsonDynamicMessageDoc.copy(dynamicMessageDocId = None)",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateDynamicMessageDoc))"
+ }
+ },
+ "getBankLevelDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicMessageDoc)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Get Bank Level Dynamic Message Doc\"",
+ "description": "s\"\"\"Get a Bank Level Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "jsonDynamicMessageDoc",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicMessageDoc))"
+ }
+ },
+ "getAllBankLevelDynamicMessageDocs": {
+ "partial_function_name_raw": "nameOf(getAllBankLevelDynamicMessageDocs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-message-docs\"",
+ "summary": "\"Get all Bank Level Dynamic Message Docs\"",
+ "description": "s\"\"\"Get all Bank Level Dynamic Message Docs.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\"dynamic-message-docs\", jsonDynamicMessageDoc :: Nil)",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllDynamicMessageDocs))"
+ }
+ },
+ "deleteBankLevelDynamicMessageDoc": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelDynamicMessageDoc)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID\"",
+ "summary": "\"Delete Bank Level Dynamic Message Doc\"",
+ "description": "s\"\"\"Delete a Bank Level Dynamic Message Doc.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicMessageDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelDynamicMessageDoc))"
+ }
+ },
+ "createEndpointMapping": {
+ "partial_function_name_raw": "nameOf(createEndpointMapping)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/endpoint-mappings\"",
+ "summary": "\"Create Endpoint Mapping\"",
+ "description": "s\"\"\"Create an Endpoint Mapping.\n |\n |Note: at moment only support the dynamic endpoints\n |\"\"\"",
+ "example_request_body": "endpointMappingRequestBodyExample",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateEndpointMapping))"
+ }
+ },
+ "updateEndpointMapping": {
+ "partial_function_name_raw": "nameOf(updateEndpointMapping)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Update Endpoint Mapping\"",
+ "description": "s\"\"\"Update an Endpoint Mapping.\n |\"\"\"",
+ "example_request_body": "endpointMappingRequestBodyExample",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateEndpointMapping))"
+ }
+ },
+ "getEndpointMapping": {
+ "partial_function_name_raw": "nameOf(getEndpointMapping)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Get Endpoint Mapping by Id\"",
+ "description": "s\"\"\"Get an Endpoint Mapping by ENDPOINT_MAPPING_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEndpointMapping))"
+ }
+ },
+ "getAllEndpointMappings": {
+ "partial_function_name_raw": "nameOf(getAllEndpointMappings)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/endpoint-mappings\"",
+ "summary": "\"Get all Endpoint Mappings\"",
+ "description": "s\"\"\"Get all Endpoint Mappings.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"endpoint-mappings\",\n endpointMappingResponseBodyExample :: Nil\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllEndpointMappings))"
+ }
+ },
+ "deleteEndpointMapping": {
+ "partial_function_name_raw": "nameOf(deleteEndpointMapping)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Delete Endpoint Mapping\"",
+ "description": "s\"\"\"Delete a Endpoint Mapping.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteEndpointMapping))"
+ }
+ },
+ "createBankLevelEndpointMapping": {
+ "partial_function_name_raw": "nameOf(createBankLevelEndpointMapping)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoint-mappings\"",
+ "summary": "\"Create Bank Level Endpoint Mapping\"",
+ "description": "s\"\"\"Create an Bank Level Endpoint Mapping.\n |\n |Note: at moment only support the dynamic endpoints\n |\"\"\"",
+ "example_request_body": "endpointMappingRequestBodyExample",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelEndpointMapping, canCreateEndpointMapping))"
+ }
+ },
+ "updateBankLevelEndpointMapping": {
+ "partial_function_name_raw": "nameOf(updateBankLevelEndpointMapping)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Update Bank Level Endpoint Mapping\"",
+ "description": "s\"\"\"Update an Bank Level Endpoint Mapping.\n |\"\"\"",
+ "example_request_body": "endpointMappingRequestBodyExample",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankLevelEndpointMapping, canUpdateEndpointMapping))"
+ }
+ },
+ "getBankLevelEndpointMapping": {
+ "partial_function_name_raw": "nameOf(getBankLevelEndpointMapping)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Get Bank Level Endpoint Mapping\"",
+ "description": "s\"\"\"Get an Bank Level Endpoint Mapping by ENDPOINT_MAPPING_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "endpointMappingResponseBodyExample",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelEndpointMapping, canGetEndpointMapping))"
+ }
+ },
+ "getAllBankLevelEndpointMappings": {
+ "partial_function_name_raw": "nameOf(getAllBankLevelEndpointMappings)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoint-mappings\"",
+ "summary": "\"Get all Bank Level Endpoint Mappings\"",
+ "description": "s\"\"\"Get all Bank Level Endpoint Mappings.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"endpoint-mappings\",\n endpointMappingResponseBodyExample :: Nil\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAllBankLevelEndpointMappings, canGetAllEndpointMappings))"
+ }
+ },
+ "deleteBankLevelEndpointMapping": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelEndpointMapping)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID\"",
+ "summary": "\"Delete Bank Level Endpoint Mapping\"",
+ "description": "s\"\"\"Delete a Bank Level Endpoint Mapping.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BooleanBody(true)",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagEndpointMapping)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelEndpointMapping, canDeleteEndpointMapping))"
+ }
+ },
+ "updateAtmSupportedCurrencies": {
+ "partial_function_name_raw": "nameOf(updateAtmSupportedCurrencies)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/supported-currencies\"",
+ "summary": "\"Update ATM Supported Currencies\"",
+ "description": "s\"\"\"Update ATM Supported Currencies.\n |\"\"\"",
+ "example_request_body": "supportedCurrenciesJson",
+ "success_response_body": "atmSupportedCurrenciesJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "updateAtmSupportedLanguages": {
+ "partial_function_name_raw": "nameOf(updateAtmSupportedLanguages)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/supported-languages\"",
+ "summary": "\"Update ATM Supported Languages\"",
+ "description": "s\"\"\"Update ATM Supported Languages.\n |\"\"\"",
+ "example_request_body": "supportedLanguagesJson",
+ "success_response_body": "atmSupportedLanguagesJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "updateAtmAccessibilityFeatures": {
+ "partial_function_name_raw": "nameOf(updateAtmAccessibilityFeatures)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/accessibility-features\"",
+ "summary": "\"Update ATM Accessibility Features\"",
+ "description": "s\"\"\"Update ATM Accessibility Features.\n |\"\"\"",
+ "example_request_body": "accessibilityFeaturesJson",
+ "success_response_body": "atmAccessibilityFeaturesJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "updateAtmServices": {
+ "partial_function_name_raw": "nameOf(updateAtmServices)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/services\"",
+ "summary": "\"Update ATM Services\"",
+ "description": "s\"\"\"Update ATM Services.\n |\"\"\"",
+ "example_request_body": "atmServicesJson",
+ "success_response_body": "atmServicesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "updateAtmNotes": {
+ "partial_function_name_raw": "nameOf(updateAtmNotes)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/notes\"",
+ "summary": "\"Update ATM Notes\"",
+ "description": "s\"\"\"Update ATM Notes.\n |\"\"\"",
+ "example_request_body": "atmNotesJson",
+ "success_response_body": "atmNotesResponseJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "updateAtmLocationCategories": {
+ "partial_function_name_raw": "nameOf(updateAtmLocationCategories)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/location-categories\"",
+ "summary": "\"Update ATM Location Categories\"",
+ "description": "s\"\"\"Update ATM Location Categories.\n |\"\"\"",
+ "example_request_body": "atmLocationCategoriesJsonV400",
+ "success_response_body": "atmLocationCategoriesResponseJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "createAtm": {
+ "partial_function_name_raw": "nameOf(createAtm)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Create ATM\"",
+ "description": "s\"\"\"Create ATM.\"\"\"",
+ "example_request_body": "atmJsonV400",
+ "success_response_body": "atmJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAtm, canCreateAtmAtAnyBank))"
+ }
+ },
+ "updateAtm": {
+ "partial_function_name_raw": "nameOf(updateAtm)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"UPDATE ATM\"",
+ "description": "s\"\"\"Update ATM.\"\"\"",
+ "example_request_body": "atmJsonV400.copy(id = None)",
+ "success_response_body": "atmJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAtm, canUpdateAtmAtAnyBank))"
+ }
+ },
+ "deleteAtm": {
+ "partial_function_name_raw": "nameOf(deleteAtm)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Delete ATM\"",
+ "description": "s\"\"\"Delete ATM.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAtmAtAnyBank, canDeleteAtm))"
+ }
+ },
+ "getAtms": {
+ "partial_function_name_raw": "nameOf(getAtms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Get Bank ATMS\"",
+ "description": "s\"\"\"Returns information about ATMs for a single bank specified by BANK_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |Pagination:\n |\n |By default, 100 records are returned.\n |\n |You can use the url query parameters *limit* and *offset* for pagination\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmsJsonV400",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "getAtm": {
+ "partial_function_name_raw": "nameOf(getAtm)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Get Bank ATM\"",
+ "description": "s\"\"\"Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |${userAuthenticationMessage(!getAtmsIsPublic)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "createSystemLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(createSystemLevelEndpointTag)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/endpoints/OPERATION_ID/tags\"",
+ "summary": "\"Create System Level Endpoint Tag\"",
+ "description": "s\"\"\"Create System Level Endpoint Tag\n |\n |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds\n |\n |\"\"\".stripMargin",
+ "example_request_body": "endpointTagJson400",
+ "success_response_body": "bankLevelEndpointTagResponseJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSystemLevelEndpointTag))"
+ }
+ },
+ "updateSystemLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(updateSystemLevelEndpointTag)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID\"",
+ "summary": "\"Update System Level Endpoint Tag\"",
+ "description": "s\"\"\"Update System Level Endpoint Tag, you can only update the tag_name here, operation_id can not be updated.\n |\n |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds\n |\n |\"\"\".stripMargin",
+ "example_request_body": "endpointTagJson400",
+ "success_response_body": "bankLevelEndpointTagResponseJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n EndpointTagNotFoundByEndpointTagId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSystemLevelEndpointTag))"
+ }
+ },
+ "getSystemLevelEndpointTags": {
+ "partial_function_name_raw": "nameOf(getSystemLevelEndpointTags)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/endpoints/OPERATION_ID/tags\"",
+ "summary": "\"Get System Level Endpoint Tags\"",
+ "description": "s\"\"\"Get System Level Endpoint Tags.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankLevelEndpointTagResponseJson400 :: Nil",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLevelEndpointTag))"
+ }
+ },
+ "deleteSystemLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(deleteSystemLevelEndpointTag)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID\"",
+ "summary": "\"Delete System Level Endpoint Tag\"",
+ "description": "s\"\"\"Delete System Level Endpoint Tag.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemLevelEndpointTag))"
+ }
+ },
+ "createBankLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(createBankLevelEndpointTag)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoints/OPERATION_ID/tags\"",
+ "summary": "\"Create Bank Level Endpoint Tag\"",
+ "description": "s\"\"\"Create Bank Level Endpoint Tag\n |\n |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds\n |\n |\n |\"\"\".stripMargin",
+ "example_request_body": "endpointTagJson400",
+ "success_response_body": "bankLevelEndpointTagResponseJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelEndpointTag))"
+ }
+ },
+ "updateBankLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(updateBankLevelEndpointTag)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID\"",
+ "summary": "\"Update Bank Level Endpoint Tag\"",
+ "description": "s\"\"\"Update Endpoint Tag, you can only update the tag_name here, operation_id can not be updated.\n |\n |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds\n |\n |\"\"\".stripMargin",
+ "example_request_body": "endpointTagJson400",
+ "success_response_body": "bankLevelEndpointTagResponseJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n EndpointTagNotFoundByEndpointTagId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankLevelEndpointTag))"
+ }
+ },
+ "getBankLevelEndpointTags": {
+ "partial_function_name_raw": "nameOf(getBankLevelEndpointTags)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoints/OPERATION_ID/tags\"",
+ "summary": "\"Get Bank Level Endpoint Tags\"",
+ "description": "s\"\"\"Get Bank Level Endpoint Tags.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankLevelEndpointTagResponseJson400 :: Nil",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelEndpointTag))"
+ }
+ },
+ "deleteBankLevelEndpointTag": {
+ "partial_function_name_raw": "nameOf(deleteBankLevelEndpointTag)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID\"",
+ "summary": "\"Delete Bank Level Endpoint Tag\"",
+ "description": "s\"\"\"Delete Bank Level Endpoint Tag.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "Full(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankLevelEndpointTag))"
+ }
+ },
+ "getMySpaces": {
+ "partial_function_name_raw": "nameOf(getMySpaces)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/spaces\"",
+ "summary": "\"Get My Spaces\"",
+ "description": "s\"\"\"Get My Spaces.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "mySpaces",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagUser)"
+ },
+ "getProducts": {
+ "partial_function_name_raw": "\"getProducts\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Get Products\"",
+ "description": "s\"\"\"Returns information about the financial products offered by a bank specified by BANK_ID including:\n |\n |* Name\n |* Code\n |* Parent Product Code\n |* More info URL\n |* Terms And Conditions URL\n |* Description\n |* Terms and Conditions\n |* License the data under this endpoint is released under\n |\n |The combination of bank_id and product_code is unique.\n |\n |Can filter with attributes name and values.\n |URL params example: /banks/some-bank-id/products?&limit=50&offset=1\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "createProduct": {
+ "partial_function_name_raw": "nameOf(createProduct)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Create Product\"",
+ "description": "s\"\"\"Create or Update Product for the Bank.\n |\n |\n |Typical Super Family values / Asset classes are:\n |\n |Debt\n |Equity\n |FX\n |Commodity\n |Derivative\n |\n |$productHiearchyAndCollectionNote\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\n |\"\"\"",
+ "example_request_body": "putProductJsonV400",
+ "success_response_body": "productJsonV400.copy(attributes = None, fees = None)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProduct, canCreateProductAtAnyBank))"
+ }
+ },
+ "getProduct": {
+ "partial_function_name_raw": "nameOf(getProduct)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Get Bank Product\"",
+ "description": "s\"\"\"Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including:\n |\n |* Name\n |* Code\n |* Parent Product Code\n |* More info URL\n |* Description\n |* Terms and Conditions\n |* Description\n |* Meta\n |* Attributes\n |* Fees\n |\n |The combination of bank_id and product_code is unique.\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "createCustomerMessage": {
+ "partial_function_name_raw": "nameOf(createCustomerMessage)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/messages\"",
+ "summary": "\"Create Customer Message\"",
+ "description": "s\"\"\"\n |Create a message for the customer specified by CUSTOMER_ID\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "createMessageJsonV400",
+ "success_response_body": "successMessage",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound\n )",
+ "tags": "List(apiTagMessage, apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomerMessage))"
+ }
+ },
+ "getCustomerMessages": {
+ "partial_function_name_raw": "nameOf(getCustomerMessages)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/messages\"",
+ "summary": "\"Get Customer Messages for a Customer\"",
+ "description": "s\"\"\"Get messages for the customer specified by CUSTOMER_ID\n ${userAuthenticationMessage(true)}\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerMessagesJsonV400",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, $BankNotFound, UnknownError)",
+ "tags": "List(apiTagMessage, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerMessages))"
+ }
+ },
+ "createSystemAccountNotificationWebhook": {
+ "partial_function_name_raw": "nameOf(createSystemAccountNotificationWebhook)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/web-hooks/account/notifications/on-create-transaction\"",
+ "summary": "\"Create system level Account Notification Webhook\"",
+ "description": "s\"\"\"\n |Create a notification Webhook that will fire for all accounts on the system.\n |\n |$generalWebHookInfo\n |\n |$accountNotificationWebhookInfo\n |\n |\"\"\"",
+ "example_request_body": "accountNotificationWebhookPostJson",
+ "success_response_body": "systemAccountNotificationWebhookJson",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagWebhook :: apiTagBank :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSystemAccountNotificationWebhook))"
+ }
+ },
+ "createBankAccountNotificationWebhook": {
+ "partial_function_name_raw": "nameOf(createBankAccountNotificationWebhook)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/web-hooks/account/notifications/on-create-transaction\"",
+ "summary": "\"Create bank level Account Notification Webhook\"",
+ "description": "s\"\"\"Create a notification Webhook that will fire for all accounts on the specified Bank.\n |\n |$generalWebHookInfo\n |\n |$accountNotificationWebhookInfo\n |\n |\"\"\"",
+ "example_request_body": "accountNotificationWebhookPostJson",
+ "success_response_body": "bankAccountNotificationWebhookJson",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "apiTagWebhook :: apiTagBank :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccountNotificationWebhookAtOneBank))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v5_0_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v5_0_0.json
new file mode 100644
index 0000000000..4592a36035
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v5_0_0.json
@@ -0,0 +1,516 @@
+{
+ "schema_version": 1,
+ "version": "v5_0_0",
+ "source_file": "obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 39,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "\"root\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Hosted at information\n |* Energy source information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJson400",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getBank": {
+ "partial_function_name_raw": "nameOf(getBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID\"",
+ "summary": "\"Get Bank\"",
+ "description": "\"\"\"Get the bank specified by BANK_ID\n |Returns information about a single bank specified by BANK_ID including:\n |\n |* Bank code and full name of bank\n |* Logo URL\n |* Website\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankJson500",
+ "error_response_bodies": "List(UnknownError, BankNotFound)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "createBank": {
+ "partial_function_name_raw": "\"createBank\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Create Bank\"",
+ "description": "s\"\"\"Create a new bank (Authenticated access).\n |\n |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.\n |Thus the User can manage the bank they create and assign Roles to other Users.\n |\n |Only SANDBOX mode (i.e. when connector=mapped in properties file)\n |The settlement accounts are automatically created by the system when the bank is created.\n |Name and account id are created in accordance to the next rules:\n | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)\n | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)\n |\n |\"\"\"",
+ "example_request_body": "postBankJson500",
+ "success_response_body": "bankJson500",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n InsufficientAuthorisationToCreateBank,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBank))"
+ }
+ },
+ "updateBank": {
+ "partial_function_name_raw": "\"updateBank\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Update Bank\"",
+ "description": "s\"\"\"Update an existing bank (Authenticated access).\n |\n |\"\"\"",
+ "example_request_body": "postBankJson500",
+ "success_response_body": "bankJson500",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n BankNotFound,\n updateBankError,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBank))"
+ }
+ },
+ "createAccount": {
+ "partial_function_name_raw": "\"createAccount\"",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID\"",
+ "summary": "\"Create Account (PUT)\"",
+ "description": "\"\"\"Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID.\n |\n |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body.\n |\n |If the PUT body USER_ID *is* specified, the logged in user must have the Role canCreateAccount. Once created, the Account will be owned by the User specified by USER_ID.\n |\n |If the PUT body USER_ID is *not* specified, the account will be owned by the logged in User.\n |\n |The 'product_code' field SHOULD be a product_code from Product.\n |If the 'product_code' matches a product_code from Product, account attributes will be created that match the Product Attributes.\n |\n |Note: The Amount MUST be zero.\"\"\".stripMargin",
+ "example_request_body": "createAccountRequestJsonV500",
+ "success_response_body": "createAccountResponseJsonV310",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n BankNotFound,\n AuthenticatedUserIsRequired,\n InvalidUserId,\n InvalidAccountIdFormat,\n InvalidBankIdFormat,\n UserNotFoundById,\n UserHasMissingRoles,\n InvalidAccountBalanceAmount,\n InvalidAccountInitialBalance,\n InitialBalanceMustBeZero,\n InvalidAccountBalanceCurrency,\n AccountIdAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagAccount,apiTagOnboarding)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccount))"
+ }
+ },
+ "createUserAuthContext": {
+ "partial_function_name_raw": "nameOf(createUserAuthContext)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/auth-context\"",
+ "summary": "\"Create User Auth Context\"",
+ "description": "s\"\"\"Create User Auth Context. These key value pairs will be propagated over connector to adapter. Normally used for mapping OBP user and \n | Bank User/Customer. \n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postUserAuthContextJson",
+ "success_response_body": "userAuthContextJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n CreateUserAuthContextError,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateUserAuthContext))"
+ }
+ },
+ "getUserAuthContexts": {
+ "partial_function_name_raw": "nameOf(getUserAuthContexts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/auth-context\"",
+ "summary": "\"Get User Auth Contexts\"",
+ "description": "s\"\"\"Get User Auth Contexts for a User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userAuthContextJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(canGetUserAuthContext :: Nil)"
+ }
+ },
+ "createUserAuthContextUpdateRequest": {
+ "partial_function_name_raw": "nameOf(createUserAuthContextUpdateRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/users/current/auth-context-updates/SCA_METHOD\"",
+ "summary": "\"Create User Auth Context Update Request\"",
+ "description": "s\"\"\"Create User Auth Context Update Request.\n |${userAuthenticationMessage(true)}\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\" or \"EMAIL\". \"EMAIL\" is used for testing purposes.\n |\n |\"\"\"",
+ "example_request_body": "postUserAuthContextJson",
+ "success_response_body": "userAuthContextUpdateJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n CreateUserAuthContextError,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "answerUserAuthContextUpdateChallenge": {
+ "partial_function_name_raw": "nameOf(answerUserAuthContextUpdateChallenge)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge\"",
+ "summary": "\"Answer User Auth Context Update Challenge\"",
+ "description": "s\"\"\"\n |Answer User Auth Context Update Challenge.\n |\"\"\"",
+ "example_request_body": "postUserAuthContextUpdateJsonV310",
+ "success_response_body": "userAuthContextUpdateJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagUser :: Nil"
+ },
+ "createConsentRequest": {
+ "partial_function_name_raw": "nameOf(createConsentRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumer/consent-requests\"",
+ "summary": "\"Create Consent Request\"",
+ "description": "s\"\"\"\n |Create a Consent Request — the first step of the OBP Consent flow.\n |\n |The calling application (TPP) authenticates with Client Credentials and posts the consent details (entitlements, account_access, VRP fields, etc.). The User then completes the flow by calling Create Consent By CONSENT_REQUEST_ID.\n |\n |The Consent Request is recorded against the calling consumer (its creator).\n |\n |Optional body fields of note:\n |\n |- `consumer_id`: if set, the resulting Consent (created when the User answers this request) will be pinned to this consumer instead of the creator. Use only when the consent is intended for a different application than the one creating the request. Most TPPs should omit this field — when omitted, the resulting Consent is pinned to the creator. Note: this override is being deprecated; v6.0.0 will pin the resulting Consent to the creator unconditionally.\n |- `email` / `phone_number`: surface in the SCA challenge if the User chooses EMAIL or SMS at answer time.\n |- `valid_from` / `time_to_live`: control the lifetime of the resulting Consent.\n |\n |Authentication:\n |\n |The client needs to authenticate themselves for this request. In case of public client we use client_id and private key to obtain access token; otherwise we use client_id and client_secret. The obtained access token is used in the HTTP Bearer auth header of our request.\n |\n |Example:\n |Authorization: Bearer eXtneO-THbQtn3zvK_kQtXXfvOZyZFdBCItlPDbR2Bk.dOWqtXCtFX-tqGTVR0YrIjvAolPIVg7GZ-jz83y6nA0\n |\n |After successfully creating the Consent Request, call Create Consent By CONSENT_REQUEST_ID to finalize.\n |\n |See Glossary entry \"Authentication: Consent OBP Flow Example\" for an end-to-end walk-through.\n |\n |${applicationAccessMessage(true)}\n |\n |${userAuthenticationMessage(false)}\n |\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postConsentRequestJsonV500",
+ "success_response_body": "consentRequestResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n ConsentMaxTTL,\n X509CannotGetCertificate,\n X509GeneralError,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getConsentRequest": {
+ "partial_function_name_raw": "nameOf(getConsentRequest)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumer/consent-requests/CONSENT_REQUEST_ID\"",
+ "summary": "\"Get Consent Request\"",
+ "description": "s\"\"\"\n |Return the full payload of a previously-created Consent Request — the JSON the TPP submitted to Create Consent Request, plus the consent_request_id and the creating consumer_id.\n |\n |Use this endpoint to verify the contents of a Consent Request before the User answers it.\n |\n |Authentication: Application access (any registered consumer/application can read any Consent Request by ID).\n |\n |Note: this endpoint will be restricted to the creating consumer in v6.0.0. Until then, treat CONSENT_REQUEST_IDs as sensitive — they reveal entitlements, account routings, and contact details (email/phone) submitted at creation.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentRequestResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n ConsentMaxTTL,\n X509CannotGetCertificate,\n X509GeneralError,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getConsentByConsentRequestId": {
+ "partial_function_name_raw": "nameOf(getConsentByConsentRequestId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumer/consent-requests/CONSENT_REQUEST_ID/consents\"",
+ "summary": "\"Get Consent By Consent Request Id via Consumer\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consent By consent request id.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "createConsentByConsentRequestIdEmail": {
+ "partial_function_name_raw": "nameOf(createConsentByConsentRequestIdEmail)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumer/consent-requests/CONSENT_REQUEST_ID/EMAIL/consents\"",
+ "summary": "\"Create Consent By CONSENT_REQUEST_ID (EMAIL)\"",
+ "description": "s\"\"\"\n |Answer a Consent Request and create the resulting Consent, with an EMAIL Strong Customer Authentication challenge.\n |\n |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).\n |\n |An SCA challenge code is sent to the email address that was supplied in the Create Consent Request body. The User then completes SCA via Answer Consent Challenge, which moves the Consent from INITIATED to ACCEPTED.\n |\n |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).\n |\n |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.\n |\n |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.\n |\n |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: apiTagVrp :: Nil"
+ },
+ "createConsentByConsentRequestIdSms": {
+ "partial_function_name_raw": "nameOf(createConsentByConsentRequestIdSms)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumer/consent-requests/CONSENT_REQUEST_ID/SMS/consents\"",
+ "summary": "\"Create Consent By CONSENT_REQUEST_ID (SMS)\"",
+ "description": "s\"\"\"\n |Answer a Consent Request and create the resulting Consent, with an SMS Strong Customer Authentication challenge.\n |\n |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).\n |\n |An SCA challenge code is sent to the phone number that was supplied in the Create Consent Request body. The User then completes SCA via Answer Consent Challenge, which moves the Consent from INITIATED to ACCEPTED.\n |\n |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).\n |\n |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.\n |\n |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.\n |\n |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n ConsentRequestIsInvalid,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n MissingPropsValueAtThisInstance,\n SmsServerNotResponding,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "createConsentByConsentRequestIdImplicit": {
+ "partial_function_name_raw": "nameOf(createConsentByConsentRequestIdImplicit)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumer/consent-requests/CONSENT_REQUEST_ID/IMPLICIT/consents\"",
+ "summary": "\"Create Consent By CONSENT_REQUEST_ID (IMPLICIT)\"",
+ "description": "s\"\"\"\n |Answer a Consent Request and create the resulting Consent, without a Strong Customer Authentication challenge — the Consent is moved directly from INITIATED to ACCEPTED.\n |\n |After the TPP has called Create Consent Request (Client Credentials), the User authenticates and answers the request via this endpoint. This creates the Consent (the credential the consumer will use to access OBP on the User's behalf).\n |\n |IMPLICIT means no SCA challenge is sent. The Consent is immediately ACCEPTED. Use only in flows where the User has already been strongly authenticated by upstream means; for production use behind a public TPP, prefer EMAIL or SMS.\n |\n |Pinning: the resulting Consent is pinned to a single consumer at creation. The pinned consumer is taken from the `consumer_id` field of the original Create Consent Request body if present, otherwise from the consumer that created the Request. After creation, only that consumer can present the resulting Consent JWT — any other consumer presenting it gets ConsentNotFound (consumer mismatch).\n |\n |Each Consent Request can be answered exactly once. A second call returns ConsentRequestIsInvalid.\n |\n |The Consent's authority is bounded by the answering User's own entitlements — it cannot grant access beyond what that User already has.\n |\n |Authentication: Any authenticated User may answer a Consent Request whose CONSENT_REQUEST_ID they know. This will be tightened in v6.0.0; until then, treat CONSENT_REQUEST_IDs as sensitive.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n ConsentRequestIsInvalid,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n MissingPropsValueAtThisInstance,\n SmsServerNotResponding,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "headAtms": {
+ "partial_function_name_raw": "nameOf(headAtms)",
+ "request_verb": "\"HEAD\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Head Bank ATMS\"",
+ "description": "s\"\"\"Head Bank ATMS.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmsJsonV400",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "nameOf(createCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"\n |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.\n |Dates need to be in the format 2013-01-21T23:08:00Z\n |\n |If kyc_status is not provided, it defaults to false.\n |\n |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postCustomerJsonV500",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getCustomerOverview": {
+ "partial_function_name_raw": "nameOf(getCustomerOverview)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/customer-number-query/overview\"",
+ "summary": "\"Get Customer Overview\"",
+ "description": "s\"\"\"Gets the Customer Overview specified by customer_number and bank_code.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerOverviewJsonV500",
+ "success_response_body": "customerOverviewJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerOverview))"
+ }
+ },
+ "getCustomerOverviewFlat": {
+ "partial_function_name_raw": "nameOf(getCustomerOverviewFlat)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/customer-number-query/overview-flat\"",
+ "summary": "\"Get Customer Overview Flat\"",
+ "description": "s\"\"\"Gets the Customer Overview Flat specified by customer_number and bank_code.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerOverviewJsonV500",
+ "success_response_body": "customerOverviewFlatJsonV500",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerOverviewFlat))"
+ }
+ },
+ "getMyCustomersAtAnyBank": {
+ "partial_function_name_raw": "nameOf(getMyCustomersAtAnyBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/customers\"",
+ "summary": "\"Get My Customers\"",
+ "description": "\"\"\"Gets all Customers that are linked to me.\n |\n |Authentication via OAuth is required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJsonV210",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)"
+ },
+ "getMyCustomersAtBank": {
+ "partial_function_name_raw": "nameOf(getMyCustomersAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/customers\"",
+ "summary": "\"Get My Customers at Bank\"",
+ "description": "s\"\"\"Returns a list of Customers at the Bank that are linked to the currently authenticated User.\n |\n |\n |${userAuthenticationMessage(true)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONs",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)"
+ },
+ "getCustomersAtOneBank": {
+ "partial_function_name_raw": "nameOf(getCustomersAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Get Customers at Bank\"",
+ "description": "s\"\"\"Get Customers at Bank.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomersMinimalAtOneBank": {
+ "partial_function_name_raw": "nameOf(getCustomersMinimalAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers-minimal\"",
+ "summary": "\"Get Customers Minimal at Bank\"",
+ "description": "s\"\"\"Get Customers Minimal at Bank.\n |\n |\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersMinimalJsonV300",
+ "error_response_bodies": "List(\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersMinimalAtOneBank))"
+ }
+ },
+ "createProduct": {
+ "partial_function_name_raw": "nameOf(createProduct)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE\"",
+ "summary": "\"Create Product\"",
+ "description": "s\"\"\"Create or Update Product for the Bank.\n |\n |The combination of bank_id and product_code is unique. If a Product already exists for the bank_id and product_code, it will be updated.\n |\n |Typical Super Family values / Asset classes are:\n |\n |Debt\n |Equity\n |FX\n |Commodity\n |Derivative\n |\n |$productHiearchyAndCollectionNote\n |\n |\n |${userAuthenticationMessage(true) }\n |\n |\n |\"\"\"",
+ "example_request_body": "putProductJsonV500",
+ "success_response_body": "productJsonV400.copy(attributes = None, fees = None)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateProduct, canCreateProductAtAnyBank))"
+ }
+ },
+ "addCardForBank": {
+ "partial_function_name_raw": "nameOf(addCardForBank)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/cards\"",
+ "summary": "\"Create Card\"",
+ "description": "s\"\"\"Create Card at bank specified by BANK_ID .\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "createPhysicalCardJsonV500",
+ "success_response_body": "physicalCardJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n AllowedValuesAre,\n UnknownError\n )",
+ "tags": "List(apiTagCard)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCardsForBank))"
+ }
+ },
+ "getViewsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getViewsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Get Views for Account\"",
+ "description": "s\"\"\"#Views\n |\n |\n |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.\n |\n |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.\n |\n |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.\n |\n |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.\n |\n |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.\n |\n |**Metadata:**\n |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.\n |\n |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).\n |\n |# All\n |*Optional*\n |\n |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewsJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "deleteSystemView": {
+ "partial_function_name_raw": "\"deleteSystemView\"",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Delete System View\"",
+ "description": "\"Deletes the system view specified by VIEW_ID\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError,\n \"user does not have owner access\"\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemView))"
+ }
+ },
+ "getMetricsAtBank": {
+ "partial_function_name_raw": "nameOf(getMetricsAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics/banks/BANK_ID\"",
+ "summary": "\"Get Metrics at Bank\"",
+ "description": "s\"\"\"Get the all metrics at the Bank specified by BANK_ID\n |\n |require CanReadMetrics role\n |\n |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics\n |\n |Should be able to filter on the following metrics fields\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString\n |\n |3 limit (for pagination: defaults to 50) eg:limit=200\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |5 sort_by (defaults to date field) eg: sort_by=date\n | possible values:\n | \"url\",\n | \"date\",\n | \"username\" (or \"user_name\" for backward compatibility),\n | \"app_name\",\n | \"developer_email\",\n | \"implemented_by_partial_function\",\n | \"implemented_in_version\",\n | \"consumer_id\",\n | \"verb\"\n |\n |6 direction (defaults to date desc) eg: direction=desc\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78\n |\n |Other filters:\n |\n |7 consumer_id (if null ignore)\n |\n |8 user_id (if null ignore)\n |\n |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |10 url (if null ignore), note: can not contain '&'.\n |\n |11 app_name (if null ignore)\n |\n |12 implemented_by_partial_function (if null ignore),\n |\n |13 implemented_in_version (if null ignore)\n |\n |14 verb (if null ignore)\n |\n |15 correlation_id (if null ignore)\n |\n |16 duration (if null ignore) non digit chars will be silently omitted\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "metricsJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMetricsAtOneBank))"
+ }
+ },
+ "getSystemView": {
+ "partial_function_name_raw": "\"getSystemView\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Get System View\"",
+ "description": "s\"\"\"Get System View\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemView))"
+ }
+ },
+ "getSystemViewsIds": {
+ "partial_function_name_raw": "nameOf(getSystemViewsIds)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system-views-ids\"",
+ "summary": "\"Get Ids of System Views\"",
+ "description": "s\"\"\"Get Ids of System Views\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "viewIdsJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemView))"
+ }
+ },
+ "createSystemView": {
+ "partial_function_name_raw": "nameOf(createSystemView)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/system-views\"",
+ "summary": "\"Create System View\"",
+ "description": "s\"\"\"Create a system view\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the $canCreateSystemView entitlement.\n |\n | The 'allowed_actions' field is a list containing the names of the actions allowed through this view.\n | All the actions contained in the list will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n | System views cannot be public. In case you try to set it you will get the error $SystemViewCannotBePublicError\n | \"\"\"",
+ "example_request_body": "createSystemViewJsonV500",
+ "success_response_body": "viewJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSystemView))"
+ }
+ },
+ "updateSystemView": {
+ "partial_function_name_raw": "nameOf(updateSystemView)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Update System View\"",
+ "description": "s\"\"\"Update an existing view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateSystemViewJson500",
+ "success_response_body": "viewJsonV500",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSystemView))"
+ }
+ },
+ "createCustomerAccountLink": {
+ "partial_function_name_raw": "nameOf(createCustomerAccountLink)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customer-account-links\"",
+ "summary": "\"Create Customer Account Link\"",
+ "description": "s\"\"\"Link a Customer to a Account\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "createCustomerAccountLinkJson",
+ "success_response_body": "customerAccountLinkJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n BankAccountNotFound,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n AccountAlreadyExistsForCustomer,\n CreateCustomerAccountLinkError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomerAccountLink))"
+ }
+ },
+ "getCustomerAccountLinksByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCustomerAccountLinksByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/customer-account-links\"",
+ "summary": "\"Get Customer Account Links by CUSTOMER_ID\"",
+ "description": "s\"\"\" Get Customer Account Links by CUSTOMER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAccountLinksJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerAccountLinks))"
+ }
+ },
+ "getCustomerAccountLinksByBankIdAccountId": {
+ "partial_function_name_raw": "nameOf(getCustomerAccountLinksByBankIdAccountId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/customer-account-links\"",
+ "summary": "\"Get Customer Account Links by ACCOUNT_ID\"",
+ "description": "s\"\"\" Get Customer Account Links by ACCOUNT_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAccountLinksJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n BankAccountNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerAccountLinks))"
+ }
+ },
+ "getCustomerAccountLinkById": {
+ "partial_function_name_raw": "nameOf(getCustomerAccountLinkById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID\"",
+ "summary": "\"Get Customer Account Link by Id\"",
+ "description": "s\"\"\" Get Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerAccountLinkJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerAccountLink))"
+ }
+ },
+ "updateCustomerAccountLinkById": {
+ "partial_function_name_raw": "nameOf(updateCustomerAccountLinkById)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID\"",
+ "summary": "\"Update Customer Account Link by Id\"",
+ "description": "s\"\"\" Update Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "updateCustomerAccountLinkJson",
+ "success_response_body": "customerAccountLinkJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateCustomerAccountLink))"
+ }
+ },
+ "deleteCustomerAccountLinkById": {
+ "partial_function_name_raw": "nameOf(deleteCustomerAccountLinkById)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/customer-account-links/CUSTOMER_ACCOUNT_LINK_ID\"",
+ "summary": "\"Delete Customer Account Link\"",
+ "description": "s\"\"\" Delete Customer Account Link by CUSTOMER_ACCOUNT_LINK_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCustomerAccountLink))"
+ }
+ },
+ "getAdapterInfo": {
+ "partial_function_name_raw": "nameOf(getAdapterInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/adapter\"",
+ "summary": "\"Get Adapter Info\"",
+ "description": "s\"\"\"Get basic information about the Adapter.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "adapterInfoJsonV500",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAdapterInfo))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v5_1_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v5_1_0.json
new file mode 100644
index 0000000000..b554bd5058
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v5_1_0.json
@@ -0,0 +1,1430 @@
+{
+ "schema_version": 1,
+ "version": "v5_1_0",
+ "source_file": "obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 111,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "nameOf(root)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Hosted at information\n |* Energy source information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJson400",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "suggestedSessionTimeout": {
+ "partial_function_name_raw": "nameOf(suggestedSessionTimeout)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/ui/suggested-session-timeout\"",
+ "summary": "\"Get Suggested Session Timeout\"",
+ "description": "\"\"\"Returns information about:\n |\n |* Suggested session timeout in case of a user inactivity\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "SuggestedSessionTimeoutV510(\"300\")",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getOAuth2ServerWellKnown": {
+ "partial_function_name_raw": "\"getOAuth2ServerWellKnown\"",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/well-known\"",
+ "summary": "\"Get Well Known URIs\"",
+ "description": "\"\"\"Get the OAuth2 server's public Well Known URIs.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "oAuth2ServerJwksUrisJson",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi)"
+ },
+ "regulatedEntities": {
+ "partial_function_name_raw": "nameOf(regulatedEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/regulated-entities\"",
+ "summary": "\"Get Regulated Entities\"",
+ "description": "\"\"\"Returns information about:\n |\n |* Regulated Entities\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "regulatedEntitiesJsonV510",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagDirectory :: apiTagApi :: Nil"
+ },
+ "logCacheTraceEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheTraceEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/trace\"",
+ "summary": "\"Get Trace Level Log Cache\"",
+ "description": "\"\"\"Returns TRACE level logs from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/trace?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheTrace, canGetSystemLogCacheAll))"
+ }
+ },
+ "logCacheDebugEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheDebugEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/debug\"",
+ "summary": "\"Get Debug Level Log Cache\"",
+ "description": "\"\"\"Returns DEBUG level logs from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/debug?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheDebug, canGetSystemLogCacheAll))"
+ }
+ },
+ "logCacheInfoEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheInfoEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/info\"",
+ "summary": "\"Get Info Level Log Cache\"",
+ "description": "\"\"\"Returns INFO level logs from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/info?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheInfo, canGetSystemLogCacheAll))"
+ }
+ },
+ "logCacheWarningEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheWarningEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/warning\"",
+ "summary": "\"Get Warning Level Log Cache\"",
+ "description": "\"\"\"Returns WARNING level logs from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/warning?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheWarning, canGetSystemLogCacheAll))"
+ }
+ },
+ "logCacheErrorEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheErrorEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/error\"",
+ "summary": "\"Get Error Level Log Cache\"",
+ "description": "\"\"\"Returns ERROR level logs from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/error?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheError, canGetSystemLogCacheAll))"
+ }
+ },
+ "logCacheAllEndpoint": {
+ "partial_function_name_raw": "nameOf(logCacheAllEndpoint)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/log-cache/all\"",
+ "summary": "\"Get All Level Log Cache\"",
+ "description": "\"\"\"Returns logs of all levels from the system log cache.\n |\n |This endpoint supports pagination via the following optional query parameters:\n |* limit - Maximum number of log entries to return\n |* offset - Number of log entries to skip (for pagination)\n |\n |Example: GET /system/log-cache/all?limit=50&offset=100\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "apiTagSystem :: apiTagApi :: apiTagLogCache :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLogCacheAll))"
+ }
+ },
+ "getRegulatedEntityById": {
+ "partial_function_name_raw": "nameOf(getRegulatedEntityById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID\"",
+ "summary": "\"Get Regulated Entity\"",
+ "description": "\"\"\"Get Regulated Entity By REGULATED_ENTITY_ID\n \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "regulatedEntityJsonV510",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagDirectory :: apiTagApi :: Nil"
+ },
+ "createRegulatedEntity": {
+ "partial_function_name_raw": "nameOf(createRegulatedEntity)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/regulated-entities\"",
+ "summary": "\"Create Regulated Entity\"",
+ "description": "s\"\"\"Create Regulated Entity\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "regulatedEntityPostJsonV510",
+ "success_response_body": "regulatedEntityJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateRegulatedEntity))"
+ }
+ },
+ "deleteRegulatedEntity": {
+ "partial_function_name_raw": "nameOf(deleteRegulatedEntity)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID\"",
+ "summary": "\"Delete Regulated Entity\"",
+ "description": "s\"\"\"Delete Regulated Entity specified by REGULATED_ENTITY_ID\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteRegulatedEntity))"
+ }
+ },
+ "waitingForGodot": {
+ "partial_function_name_raw": "nameOf(waitingForGodot)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/waiting-for-godot\"",
+ "summary": "\"Waiting For Godot\"",
+ "description": "\"\"\"Waiting For Godot\n |\n |Uses query parameter \"sleep\" in milliseconds.\n |For instance: .../waiting-for-godot?sleep=50 means postpone response in 50 milliseconds.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "WaitingForGodotJsonV510(sleep_in_milliseconds = 50)",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getAllApiCollections": {
+ "partial_function_name_raw": "nameOf(getAllApiCollections)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/api-collections\"",
+ "summary": "\"Get All API Collections\"",
+ "description": "s\"\"\"Get All API Collections.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiCollectionsJson400",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)",
+ "extra_named_args": {
+ "roles": "Some(canGetAllApiCollections :: Nil)"
+ }
+ },
+ "createAgent": {
+ "partial_function_name_raw": "nameOf(createAgent)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/agents\"",
+ "summary": "\"Create Agent\"",
+ "description": "s\"\"\"\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postAgentJsonV510",
+ "success_response_body": "agentJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n AgentNumberAlreadyExists,\n CreateAgentError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)"
+ },
+ "updateAgentStatus": {
+ "partial_function_name_raw": "nameOf(updateAgentStatus)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/agents/AGENT_ID\"",
+ "summary": "\"Update Agent status\"",
+ "description": "s\"\"\"\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "putAgentJsonV510",
+ "success_response_body": "agentJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n AgentNotFound,\n AgentAccountLinkNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(canUpdateAgentStatusAtAnyBank :: canUpdateAgentStatusAtOneBank :: Nil)"
+ }
+ },
+ "getAgent": {
+ "partial_function_name_raw": "nameOf(getAgent)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/agents/AGENT_ID\"",
+ "summary": "\"Get Agent\"",
+ "description": "s\"\"\"Get Agent.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "agentJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n AgentNotFound,\n AgentAccountLinkNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "createNonPersonalUserAttribute": {
+ "partial_function_name_raw": "nameOf(createNonPersonalUserAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/non-personal/attributes\"",
+ "summary": "\"Create Non Personal User Attribute\"",
+ "description": "s\"\"\" Create Non Personal User Attribute\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "userAttributeJsonV510",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateNonPersonalUserAttribute))"
+ }
+ },
+ "deleteNonPersonalUserAttribute": {
+ "partial_function_name_raw": "nameOf(deleteNonPersonalUserAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/non-personal/attributes/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Non Personal User Attribute\"",
+ "description": "s\"\"\"Delete the Non Personal User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteNonPersonalUserAttribute))"
+ }
+ },
+ "getNonPersonalUserAttributes": {
+ "partial_function_name_raw": "nameOf(getNonPersonalUserAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/non-personal/attributes\"",
+ "summary": "\"Get Non Personal User Attributes\"",
+ "description": "s\"\"\"Get Non Personal User Attribute for a user specified by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetNonPersonalUserAttributes))"
+ }
+ },
+ "syncExternalUser": {
+ "partial_function_name_raw": "nameOf(syncExternalUser)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/PROVIDER/PROVIDER_ID/sync\"",
+ "summary": "\"Sync User\"",
+ "description": "s\"\"\"The endpoint is used to create or sync an OBP User with User from an external identity provider.\n |PROVIDER is the host of the provider e.g. a Keycloak Host.\n |PROVIDER_ID is the unique identifier for the User at the PROVIDER.\n |At the end of the process, a User will exist in OBP with the Account Access records defined by the CBS.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "refresUserJson",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canSyncUser))"
+ }
+ },
+ "getAccountsHeldByUserAtBank": {
+ "partial_function_name_raw": "nameOf(getAccountsHeldByUserAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/banks/BANK_ID/accounts-held\"",
+ "summary": "\"Get Accounts Held By User\"",
+ "description": "s\"\"\"Get Accounts held by the User if even the User has not been assigned the owner View yet.\n |\n |Can be used to onboard the account to the API - since all other account and transaction endpoints require views to be assigned.\n |\n |${accountTypeFilterText(\"/users/USER_ID/banks/BANK_ID/accounts-held\")}\n |\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsHeldJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountsHeldAtOneBank, canGetAccountsHeldAtAnyBank))"
+ }
+ },
+ "getAccountsHeldByUser": {
+ "partial_function_name_raw": "nameOf(getAccountsHeldByUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/accounts-held\"",
+ "summary": "\"Get Accounts Held By User\"",
+ "description": "s\"\"\"Get Accounts held by the User if even the User has not been assigned the owner View yet.\n |\n |Can be used to onboard the account to the API - since all other account and transaction endpoints require views to be assigned.\n |\n |${accountTypeFilterText(\"/users/USER_ID/accounts-held\")}\n |\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "coreAccountsHeldJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountsHeldAtAnyBank))"
+ }
+ },
+ "getEntitlementsAndPermissions": {
+ "partial_function_name_raw": "nameOf(getEntitlementsAndPermissions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/entitlements-and-permissions\"",
+ "summary": "\"Get Entitlements and Permissions for a User\"",
+ "description": "s\"\"\"\n |\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UserHasMissingRoles,\n UnknownError)",
+ "tags": "List(apiTagRole, apiTagEntitlement, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyUserAtAnyBank))"
+ }
+ },
+ "customViewNamesCheck": {
+ "partial_function_name_raw": "nameOf(customViewNamesCheck)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system/integrity/custom-view-names-check\"",
+ "summary": "\"Check Custom View Names\"",
+ "description": "s\"\"\"Check custom view names.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CheckSystemIntegrityJsonV510(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemIntegrity)",
+ "extra_named_args": {
+ "roles": "Some(canGetSystemIntegrity :: Nil)"
+ }
+ },
+ "systemViewNamesCheck": {
+ "partial_function_name_raw": "nameOf(systemViewNamesCheck)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system/integrity/system-view-names-check\"",
+ "summary": "\"Check System View Names\"",
+ "description": "s\"\"\"Check system view names.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CheckSystemIntegrityJsonV510(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemIntegrity)",
+ "extra_named_args": {
+ "roles": "Some(canGetSystemIntegrity :: Nil)"
+ }
+ },
+ "accountAccessUniqueIndexCheck": {
+ "partial_function_name_raw": "nameOf(accountAccessUniqueIndexCheck)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system/integrity/account-access-unique-index-1-check\"",
+ "summary": "\"Check Unique Index at Account Access\"",
+ "description": "s\"\"\"Check unique index at account access table.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CheckSystemIntegrityJsonV510(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemIntegrity)",
+ "extra_named_args": {
+ "roles": "Some(canGetSystemIntegrity :: Nil)"
+ }
+ },
+ "accountCurrencyCheck": {
+ "partial_function_name_raw": "nameOf(accountCurrencyCheck)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system/integrity/banks/BANK_ID/account-currency-check\"",
+ "summary": "\"Check for Sensible Currencies\"",
+ "description": "s\"\"\"Check for sensible currencies at Bank Account model\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CheckSystemIntegrityJsonV510(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemIntegrity)",
+ "extra_named_args": {
+ "roles": "Some(canGetSystemIntegrity :: Nil)"
+ }
+ },
+ "getCurrenciesAtBank": {
+ "partial_function_name_raw": "nameOf(getCurrenciesAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/currencies\"",
+ "summary": "\"Get Currencies at a Bank\"",
+ "description": "\"\"\"Get Currencies specified by BANK_ID\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "currenciesJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagFx)"
+ },
+ "orphanedAccountCheck": {
+ "partial_function_name_raw": "nameOf(orphanedAccountCheck)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system/integrity/banks/BANK_ID/orphaned-account-check\"",
+ "summary": "\"Check for Orphaned Accounts\"",
+ "description": "s\"\"\"Check for orphaned accounts at Bank Account model\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CheckSystemIntegrityJsonV510(true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemIntegrity)",
+ "extra_named_args": {
+ "roles": "Some(canGetSystemIntegrity :: Nil)"
+ }
+ },
+ "createAtmAttribute": {
+ "partial_function_name_raw": "nameOf(createAtmAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/attributes\"",
+ "summary": "\"Create ATM Attribute\"",
+ "description": "s\"\"\" Create ATM Attribute\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "atmAttributeJsonV510",
+ "success_response_body": "atmAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM, apiTagAtmAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAtmAttribute, canCreateAtmAttributeAtAnyBank))"
+ }
+ },
+ "getAgents": {
+ "partial_function_name_raw": "nameOf(getAgents)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/agents\"",
+ "summary": "\"Get Agents at Bank\"",
+ "description": "s\"\"\"Get Agents at Bank.\n |\n |${userAuthenticationMessage(false)}\n |\n |${urlParametersDocument(true, true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "minimalAgentsJsonV510",
+ "error_response_bodies": "List(\n $BankNotFound,\n AgentsNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "getAtmAttributes": {
+ "partial_function_name_raw": "nameOf(getAtmAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/attributes\"",
+ "summary": "\"Get ATM Attributes\"",
+ "description": "s\"\"\" Get ATM Attributes\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmAttributesResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM, apiTagAtmAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAtmAttribute, canGetAtmAttributeAtAnyBank))"
+ }
+ },
+ "getAtmAttribute": {
+ "partial_function_name_raw": "nameOf(getAtmAttribute)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID\"",
+ "summary": "\"Get ATM Attribute By ATM_ATTRIBUTE_ID\"",
+ "description": "s\"\"\" Get ATM Attribute By ATM_ATTRIBUTE_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM, apiTagAtmAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAtmAttribute, canGetAtmAttributeAtAnyBank))"
+ }
+ },
+ "updateAtmAttribute": {
+ "partial_function_name_raw": "nameOf(updateAtmAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID\"",
+ "summary": "\"Update ATM Attribute\"",
+ "description": "s\"\"\" Update ATM Attribute.\n |\n |Update an ATM Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "atmAttributeJsonV510",
+ "success_response_body": "atmAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagATM, apiTagAtmAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAtmAttribute, canUpdateAtmAttributeAtAnyBank))"
+ }
+ },
+ "deleteAtmAttribute": {
+ "partial_function_name_raw": "nameOf(deleteAtmAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID/attributes/ATM_ATTRIBUTE_ID\"",
+ "summary": "\"Delete ATM Attribute\"",
+ "description": "s\"\"\" Delete ATM Attribute\n |\n |Delete a Atm Attribute by its id.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagATM, apiTagAtmAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAtmAttribute, canDeleteAtmAttributeAtAnyBank))"
+ }
+ },
+ "updateConsentStatusByConsent": {
+ "partial_function_name_raw": "nameOf(updateConsentStatusByConsent)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/consents/CONSENT_ID\"",
+ "summary": "\"Update Consent Status by CONSENT_ID\"",
+ "description": "s\"\"\"\n |\n |\n |This endpoint is used to update the Status of Consent.\n |\n |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(\", \")}.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PutConsentStatusJsonV400(status = \"AUTHORISED\")",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt = \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"AUTHORISED\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n ConsentNotFound,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsentStatusAtOneBank, canUpdateConsentStatusAtAnyBank))"
+ }
+ },
+ "updateConsentAccountAccessByConsentId": {
+ "partial_function_name_raw": "nameOf(updateConsentAccountAccessByConsentId)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/consents/CONSENT_ID/account-access\"",
+ "summary": "\"Update Consent Account Access by CONSENT_ID\"",
+ "description": "s\"\"\"\n |\n |This endpoint is used to update the Account Access of Consent.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PutConsentPayloadJsonV510(\n access = ConsentAccessJson(\n accounts = Option(List(ConsentAccessAccountsJson(\n iban = Some(ExampleValue.ibanExample.value),\n bban = None,\n pan = None,\n maskedPan = None,\n msisdn = None,\n currency = None,\n )))\n )\n )",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt = \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"AUTHORISED\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n ConsentNotFound,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsentAccountAccessAtOneBank, canUpdateConsentAccountAccessAtAnyBank))"
+ }
+ },
+ "updateConsentUserIdByConsentId": {
+ "partial_function_name_raw": "nameOf(updateConsentUserIdByConsentId)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/consents/CONSENT_ID/created-by-user\"",
+ "summary": "\"Update Created by User of Consent by CONSENT_ID\"",
+ "description": "s\"\"\"\n |\n |This endpoint is used to Update the User bound to a consent.\n |\n |In general we would not expect for a management user to set the User bound to a consent, but there may be\n |some use cases where this workflow is useful.\n |\n |If successful, the \"Created by User ID\" field in the OBP Consent table will be updated.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PutConsentUserJsonV400(user_id = \"ed7a7c01-db37-45cc-ba12-0ae8891c195c\")",
+ "success_response_body": "ConsentChallengeJsonV310(\n consent_id = \"9d429899-24f5-42c8-8565-943ffa6a7945\",\n jwt = \"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4\",\n status = \"AUTHORISED\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n ConsentNotFound,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsentUserAtOneBank, canUpdateConsentUserAtAnyBank))"
+ }
+ },
+ "getMyConsentsByBank": {
+ "partial_function_name_raw": "nameOf(getMyConsentsByBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/my/consents\"",
+ "summary": "\"Get My Consents at Bank\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents created by a current User at the specified Bank.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |3 status (ignore if omitted)\n |\n |4 sort_by (defaults to created_date:desc) eg: sort_by=created_date:desc\n |\n |Note: This endpoint only returns consents that explicitly reference the specified BANK_ID.\n |Consents created before the consent_item join table was introduced will not appear in results.\n |\n |eg: /banks/BANK_ID/my/consents?limit=10&offset=0&sort_by=created_date:desc\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsInfoJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getMyConsents": {
+ "partial_function_name_raw": "nameOf(getMyConsents)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/consents\"",
+ "summary": "\"Get My Consents\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents created by the current User.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |3 status (ignore if omitted)\n |\n |4 sort_by (defaults to created_date:desc) eg: sort_by=created_date:desc\n |\n |eg: /my/consents?limit=10&offset=0&sort_by=created_date:desc\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsInfoJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getConsentsAtBank": {
+ "partial_function_name_raw": "nameOf(getConsentsAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consents/banks/BANK_ID\"",
+ "summary": "\"Get Consents at Bank\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents at Bank by BANK_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |3 consumer_id (ignore if omitted)\n |\n |4 user_id (ignore if omitted)\n |\n |5 status (ignore if omitted)\n |\n |eg: /management/consents/banks/BANK_ID?&consumer_id=78&limit=10&offset=10\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsentsAtOneBank, canGetConsentsAtAnyBank))"
+ }
+ },
+ "getConsents": {
+ "partial_function_name_raw": "nameOf(getConsents)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consents\"",
+ "summary": "\"Get Consents\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consents.\n |\n |${userAuthenticationMessage(true)}\n |\n |1 limit (for pagination: defaults to 50) eg:limit=200\n |\n |2 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |3 consumer_id (ignore if omitted)\n |\n |4 consent_id (ignore if omitted)\n |\n |5 user_id (ignore if omitted)\n |\n |6 status (ignore if omitted)\n |\n |7 bank_id (ignore if omitted)\n |\n |8 provider_provider_id (ignore if omitted)\n |provider and provider_id values are separated by pipe char\n |eg: provider_provider_id=http%3A%2F%2Flocalhost%3A7070%2Frealms%2Fmaster|7837ee9c-3446-4d8c-9b90-301a52b4851d\n |\n |eg:/management/consents?consumer_id=78&limit=10&offset=10\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentsJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsentsAtAnyBank))"
+ }
+ },
+ "getConsentByConsentId": {
+ "partial_function_name_raw": "nameOf(getConsentByConsentId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/user/current/consents/CONSENT_ID\"",
+ "summary": "\"Get Consent By Consent Id via User\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consent By consent id.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "getConsentByConsentIdViaConsumer": {
+ "partial_function_name_raw": "nameOf(getConsentByConsentIdViaConsumer)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumer/current/consents/CONSENT_ID\"",
+ "summary": "\"Get Consent By Consent Id via Consumer\"",
+ "description": "s\"\"\"\n |\n |This endpoint gets the Consent By consent id.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consentJsonV500",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "revokeConsentAtBank": {
+ "partial_function_name_raw": "nameOf(revokeConsentAtBank)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/consents/CONSENT_ID\"",
+ "summary": "\"Revoke Consent at Bank\"",
+ "description": "s\"\"\"\n |Revoke Consent specified by CONSENT_ID\n |\n |There are a few reasons you might need to revoke an application’s access to a user’s account:\n | - The user explicitly wishes to revoke the application’s access\n | - You as the service provider have determined an application is compromised or malicious, and want to disable it\n | - etc.\n ||\n |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.\n |The status of the token is changed to \"REVOKED\" so the next time the revoked client makes a request, their token will fail to validate.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "revokedConsentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)",
+ "extra_named_args": {
+ "roles": "Some(List(canRevokeConsentAtBank))"
+ }
+ },
+ "selfRevokeConsent": {
+ "partial_function_name_raw": "nameOf(selfRevokeConsent)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/consent/current\"",
+ "summary": "\"Revoke Consent used in the Current Call\"",
+ "description": "s\"\"\"\n |Revoke Consent specified by Consent-Id at Request Header\n |\n |There are a few reasons you might need to revoke an application’s access to a user’s account:\n | - The user explicitly wishes to revoke the application’s access\n | - You as the service provider have determined an application is compromised or malicious, and want to disable it\n | - etc.\n ||\n |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.\n |The status of the token is changed to \"REVOKED\" so the next time the revoked client makes a request, their token will fail to validate.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "revokedConsentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "revokeMyConsent": {
+ "partial_function_name_raw": "nameOf(revokeMyConsent)",
+ "request_verb": "\"Delete\"",
+ "request_url": "\"/my/consents/CONSENT_ID\"",
+ "summary": "\"Revoke My Consent\"",
+ "description": "s\"\"\"\n |Revoke Consent for current user specified by CONSENT_ID\n |\n |There are a few reasons you might need to revoke an application’s access to a user’s account:\n | - The user explicitly wishes to revoke the application’s access\n | - You as the service provider have determined an application is compromised or malicious, and want to disable it\n | - etc.\n |\n |Please note that this endpoint only supports the case:: \"The user explicitly wishes to revoke the application’s access\"\n |\n |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user.\n |The status of the token is changed to \"REVOKED\" so the next time the revoked client makes a request, their token will fail to validate.\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "revokedConsentJsonV310",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "createConsentImplicit": {
+ "partial_function_name_raw": "nameOf(createConsentImplicit)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/consents/IMPLICIT\"",
+ "summary": "\"Create Consent (IMPLICIT)\"",
+ "description": "s\"\"\"\n |\n |This endpoint starts the process of creating a Consent.\n |\n |The Consent is created in an ${ConsentStatus.INITIATED} state.\n |\n |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD\n |SCA_METHOD is typically \"SMS\",\"EMAIL\" or \"IMPLICIT\". \"EMAIL\" is used for testing purposes. OBP mapped mode \"IMPLICIT\" is \"EMAIL\".\n |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.\n |\n |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.\n |\n |$generalObpConsentText\n |\n |${userAuthenticationMessage(true)}\n |\n |Example 1:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n |}\n |\n |Please note that consumer_id is optional field\n |Example 2:\n |{\n | \"everything\": true,\n | \"views\": [],\n | \"entitlements\": [],\n |}\n |\n |Please note if everything=false you need to explicitly specify views and entitlements\n |Example 3:\n |{\n | \"everything\": false,\n | \"views\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"account_id\": \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n | \"view_id\": \"${Constant.SYSTEM_OWNER_VIEW_ID}\"\n | }\n | ],\n | \"entitlements\": [\n | {\n | \"bank_id\": \"GENODEM1GLS\",\n | \"role_name\": \"CanGetCustomersAtOneBank\"\n | }\n | ],\n | \"consumer_id\": \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n |}\n |\n |\"\"\"",
+ "example_request_body": "postConsentImplicitJsonV310",
+ "success_response_body": "consentJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n InvalidJsonFormat,\n ConsentAllowedScaMethods,\n RolesAllowedInConsent,\n ViewsAllowedInConsent,\n ConsumerNotFoundByConsumerId,\n ConsumerIsDisabled,\n MissingPropsValueAtThisInstance,\n SmsServerNotResponding,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "mtlsClientCertificateInfo": {
+ "partial_function_name_raw": "nameOf(mtlsClientCertificateInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/mtls/certificate/current\"",
+ "summary": "\"Provide client's certificate info of a current call\"",
+ "description": "s\"\"\"\n |Provide client's certificate info of a current call specified by PSD2-CERT value at Request Header\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "certificateInfoJsonV510",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)"
+ },
+ "updateMyApiCollection": {
+ "partial_function_name_raw": "nameOf(updateMyApiCollection)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/my/api-collections/API_COLLECTION_ID\"",
+ "summary": "\"Update My Api Collection By API_COLLECTION_ID\"",
+ "description": "s\"\"\"Update Api Collection for logged in user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "postApiCollectionJson400",
+ "success_response_body": "apiCollectionJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection)"
+ },
+ "getUserByProviderAndUsername": {
+ "partial_function_name_raw": "nameOf(getUserByProviderAndUsername)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/provider/PROVIDER/username/USERNAME\"",
+ "summary": "\"Get User by USERNAME\"",
+ "description": "s\"\"\"Get user by PROVIDER and USERNAME\n |\n |Get a User by their authentication provider and username.\n |\n |**URL Parameters:**\n |\n |* PROVIDER - The authentication provider (e.g., http://127.0.0.1:8080, google.com, OBP)\n |* USERNAME - The username at that provider (e.g., obpstripe, john.doe)\n |\n |**Important:** The PROVIDER parameter can contain special characters like slashes and colons.\n |For example, if the provider is \"http://127.0.0.1:8080\", the full URL would be:\n |\n |`GET /obp/v5.1.0/users/provider/http://127.0.0.1:8080/username/obpstripe`\n |\n |The API will correctly parse the provider value even with these special characters.\n |\n |**To find valid providers**, use the GET /obp/v6.0.0/providers endpoint (available in API version 6.0.0).\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userWithNamesJsonV510",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUserLockStatus": {
+ "partial_function_name_raw": "nameOf(getUserLockStatus)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/PROVIDER/USERNAME/lock-status\"",
+ "summary": "\"Get User Lock Status\"",
+ "description": "s\"\"\"\n |Get User Login Status.\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "badLoginStatusJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadUserLockedStatus))"
+ }
+ },
+ "unlockUserByProviderAndUsername": {
+ "partial_function_name_raw": "nameOf(unlockUserByProviderAndUsername)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/users/PROVIDER/USERNAME/lock-status\"",
+ "summary": "\"Unlock the user\"",
+ "description": "s\"\"\"\n |Unlock a User.\n |\n |(Perhaps the user was locked due to multiple failed login attempts)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "badLoginStatusJson",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canUnlockUser))"
+ }
+ },
+ "lockUserByProviderAndUsername": {
+ "partial_function_name_raw": "nameOf(lockUserByProviderAndUsername)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/PROVIDER/USERNAME/locks\"",
+ "summary": "\"Lock the user\"",
+ "description": "s\"\"\"\n |Lock a User.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userLockStatusJson",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canLockUser))"
+ }
+ },
+ "validateUserByUserId": {
+ "partial_function_name_raw": "nameOf(validateUserByUserId)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/users/USER_ID\"",
+ "summary": "\"Validate a user\"",
+ "description": "s\"\"\"\n |Manually validate a User by USER_ID.\n |\n |This is an administrative endpoint that marks a user's account as validated (i.e. sets is_validated to true).\n |\n |This is useful when an administrator needs to validate a user on their behalf,\n |for example if the user did not receive the validation email, or if the email validation token has expired.\n |\n |For self-service email validation, see the Validate User Email endpoint (POST /users/email-validation).\n |\n |Authentication is Required and the user must have the canValidateUser role.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "UserValidatedJson(is_validated = true)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canValidateUser))"
+ }
+ },
+ "getAggregateMetrics": {
+ "partial_function_name_raw": "nameOf(getAggregateMetrics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/aggregate-metrics\"",
+ "summary": "\"Get Aggregate Metrics\"",
+ "description": "s\"\"\"Returns aggregate metrics on api usage eg. total count, response time (in ms), etc.\n |\n |Should be able to filter on the following fields\n |\n |eg: /management/aggregate-metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |1 from_date (defaults to the day before the current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to the current date) eg:to_date=$DateWithMsExampleString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore),\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 include_app_names (if null ignore).eg: &include_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |13 include_url_patterns (if null ignore).you can design you own SQL LIKE pattern. eg: &include_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |14 include_implemented_by_partial_functions (if null ignore).eg: &include_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |15 http_status_code (if null ignore) - Filter by HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "aggregateMetricsJSONV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagAggregateMetrics)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadAggregateMetrics))"
+ }
+ },
+ "getMetrics": {
+ "partial_function_name_raw": "nameOf(getMetrics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics\"",
+ "summary": "\"Get Metrics\"",
+ "description": "s\"\"\"Get API metrics rows. These are records of each REST API call.\n |\n |require CanReadMetrics role\n |\n |**IMPORTANT: Smart Caching & Performance**\n |\n |This endpoint uses intelligent two-tier caching to optimize performance:\n |\n |**Stable Data Cache (Long TTL):**\n |- Metrics older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} minutes) are considered immutable/stable\n |- These are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours)\n |- Used when your query's from_date is older than the stable boundary\n |\n |**Recent Data Cache (Short TTL):**\n |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds\n |- Used when your query includes recent data or has no from_date\n |\n |**STRONGLY RECOMMENDED: Always specify from_date in your queries!**\n |\n |**Why from_date matters:**\n |- Queries WITH from_date older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} mins → cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours (fast!)\n |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds (slower)\n |\n |**Examples:**\n |- `from_date=2025-01-01T00:00:00.000Z` → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours cache (historical data)\n |- `from_date=$DateWithMsExampleString` (recent date) → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds cache (recent data)\n |- No from_date (e.g., `?limit=50`) → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds cache (assumes recent data)\n |\n |For best performance on historical/reporting queries, always include a from_date parameter!\n |\n |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics\n |\n |You can filter by the following fields by applying url parameters\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date e.g.:from_date=$DateWithMsExampleString Defaults to the Unix Epoch i.e. ${theEpochTime}\n | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!\n |\n |2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}\n |\n |3 limit (for pagination: defaults to 50) eg:limit=200\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |5 sort_by (defaults to date field) eg: sort_by=date\n | possible values:\n | \"url\",\n | \"date\",\n | \"username\" (or \"user_name\" for backward compatibility),\n | \"app_name\",\n | \"developer_email\",\n | \"implemented_by_partial_function\",\n | \"implemented_in_version\",\n | \"consumer_id\",\n | \"verb\",\n | \"http_status_code\"\n |\n |6 direction (defaults to date desc) eg: direction=desc\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78\n |\n |Other filters:\n |\n |7 consumer_id (if null ignore)\n |\n |8 user_id (if null ignore)\n |\n |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |10 url (if null ignore), note: can not contain '&'.\n |\n |11 app_name (if null ignore)\n |\n |12 implemented_by_partial_function (if null ignore),\n |\n |13 implemented_in_version (if null ignore)\n |\n |14 verb (if null ignore)\n |\n |15 correlation_id (if null ignore)\n |\n |16 duration (if null ignore) - Returns calls where duration > specified value (in milliseconds). Use this to find slow API calls. eg: duration=5000 returns calls taking more than 5 seconds\n |\n |17 http_status_code (if null ignore) - Returns calls with specific HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "metricsJsonV510",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "getCustomersForUserIdsOnly": {
+ "partial_function_name_raw": "nameOf(getCustomersForUserIdsOnly)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/customers/customer_ids\"",
+ "summary": "\"Get Customers for Current User (IDs only)\"",
+ "description": "s\"\"\"Gets all Customers Ids that are linked to a User.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customersWithAttributesJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)"
+ },
+ "getCustomersByLegalName": {
+ "partial_function_name_raw": "nameOf(getCustomersByLegalName)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/legal-name\"",
+ "summary": "\"Get Customers by Legal Name\"",
+ "description": "s\"\"\"Gets the Customers specified by Legal Name.\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerLegalNameJsonV510",
+ "success_response_body": "customerJsonV310",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "createAtm": {
+ "partial_function_name_raw": "nameOf(createAtm)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Create ATM\"",
+ "description": "s\"\"\"Create ATM.\"\"\"",
+ "example_request_body": "postAtmJsonV510",
+ "success_response_body": "atmJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAtm, canCreateAtmAtAnyBank))"
+ }
+ },
+ "updateAtm": {
+ "partial_function_name_raw": "nameOf(updateAtm)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"UPDATE ATM\"",
+ "description": "s\"\"\"Update ATM.\"\"\"",
+ "example_request_body": "atmJsonV510.copy(id = None, attributes = None)",
+ "success_response_body": "atmJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAtm, canUpdateAtmAtAnyBank))"
+ }
+ },
+ "getAtms": {
+ "partial_function_name_raw": "nameOf(getAtms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms\"",
+ "summary": "\"Get Bank ATMS\"",
+ "description": "s\"\"\"Returns information about ATMs for a single bank specified by BANK_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |\n |Pagination:\n |\n |By default, 100 records are returned.\n |\n |You can use the url query parameters *limit* and *offset* for pagination\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmsJsonV510",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagATM)"
+ },
+ "getAtm": {
+ "partial_function_name_raw": "nameOf(getAtm)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Get Bank ATM\"",
+ "description": "s\"\"\"Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including:\n |\n |* Address\n |* Geo Location\n |* License the data under this endpoint is released under\n |* ATM Attributes\n |\n |\n |\n |${userAuthenticationMessage(!getAtmsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "atmJsonV510",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, BankNotFound, AtmNotFoundByAtmId, UnknownError)",
+ "tags": "List(apiTagATM)"
+ },
+ "deleteAtm": {
+ "partial_function_name_raw": "nameOf(deleteAtm)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/atms/ATM_ID\"",
+ "summary": "\"Delete ATM\"",
+ "description": "s\"\"\"Delete ATM.\n |\n |This will also delete all its attributes.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagATM)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAtmAtAnyBank, canDeleteAtm))"
+ }
+ },
+ "createConsumerDynamicRegistration": {
+ "partial_function_name_raw": "nameOf(createConsumerDynamicRegistration)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/dynamic-registration/consumers\"",
+ "summary": "\"Create a Consumer(Dynamic Registration)\"",
+ "description": "s\"\"\"Create a Consumer with full certificate validation (mTLS access) - **Recommended for PSD2/Berlin Group compliance**.\n |\n |This endpoint provides **secure, validated consumer registration** unlike the standard `/management/consumers` endpoint.\n |\n |**How it works (for comprehension flow):**\n |\n |1. **Extract JWT from request**: Parse the signed JWT from the request body\n |2. **Extract certificate**: Get certificate from `PSD2-CERT` header in PEM format\n |3. **Verify JWT signature**: Validate JWT is signed with the certificate's private key (proves possession)\n |4. **Parse JWT payload**: Extract consumer details (description, app_name, app_type, developer_email, redirect_url)\n |5. **Extract certificate info**: Parse certificate to get Common Name, Email, Organization\n |6. **Validate against Regulated Entity**: Check certificate exists in Regulated Entity registry (PSD2 requirement)\n |7. **Create consumer**: Generate credentials and create consumer record with validated certificate\n |8. **Return consumer with certificate info**: Returns consumer details including parsed certificate information\n |\n |**Certificate Validation (CRITICAL SECURITY DIFFERENCE from regular creation):**\n |\n |[YES] **JWT Signature Verification**: JWT must be signed with certificate's private key - proves TPP owns the certificate\n |[YES] **Regulated Entity Check**: Certificate must match a pre-registered Regulated Entity in the database\n |[YES] **Certificate Binding**: Certificate is permanently bound to the consumer at creation time\n |[YES] **CA Validation**: Certificate chain can be validated against trusted root CAs during API requests\n |[YES] **PSD2 Compliance**: Meets EU regulatory requirements for TPP registration\n |\n |**Security benefits vs regular consumer creation:**\n |\n || Feature | Regular Creation | Dynamic Registration |\n ||---------|-----------------|---------------------|\n || Certificate validation | [NO] None | [YES] Full validation |\n || Regulated Entity check | [NO] Not required | [YES] Required |\n || JWT signature proof | [NO] Not required | [YES] Required (proves private key possession) |\n || Self-signed certs | [YES] Accepted | [NO] Rejected |\n || PSD2 compliant | [NO] No | [YES] Yes |\n || Rogue TPP prevention | [NO] No | [YES] Yes |\n |\n |**Prerequisites:**\n |1. TPP must be registered as a Regulated Entity with their certificate\n |2. Certificate must be provided in `PSD2-CERT` request header (PEM format)\n |3. JWT must be signed with the private key corresponding to the certificate\n |4. Trust store must be configured with trusted root CAs\n |\n |**JWT Payload Structure:**\n |\n |Minimal:\n |```json\n |{ \"description\":\"TPP Application Description\" }\n |```\n |\n |Full:\n |```json\n |{\n | \"description\": \"Payment Initiation Service\",\n | \"app_name\": \"Tesobe GmbH\",\n | \"app_type\": \"Confidential\",\n | \"developer_email\": \"contact@tesobe.com\",\n | \"redirect_url\": \"https://tpp.example.com/callback\"\n |}\n |```\n |\n |**Note:** JWT must be signed with the private key that corresponds to the public key in the certificate sent via `PSD2-CERT` header.\n |\n |**Certificate Information Extraction:**\n |\n |The endpoint automatically extracts information from the certificate:\n |- Common Name (CN) → used as app_name if not provided in JWT\n |- Email Address → used as developer_email if not provided\n |- Organization (O) → used as company\n |- Certificate validity period\n |- Issuer information\n |\n |**Configuration Required:**\n |- `truststore.path.tpp_signature` - Path to trust store for CA validation\n |- `truststore.password.tpp_signature` - Trust store password\n |- Regulated Entity must be pre-registered with certificate public key\n |\n |**Error Scenarios:**\n |- JWT signature invalid → `PostJsonIsNotSigned` (400)\n |- Certificate not in Regulated Entity registry → `RegulatedEntityNotFoundByCertificate` (400)\n |- Invalid JWT format → `InvalidJsonFormat` (400)\n |- Missing PSD2-CERT header → Signature verification fails\n |\n |**This is the SECURE way to register consumers for production PSD2/Berlin Group implementations.**\n |\n |\"\"\"",
+ "example_request_body": "ConsumerJwtPostJsonV510(\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXNjcmlwdGlvbiI6IlRQUCBkZXNjcmlwdGlvbiJ9.c5gPPsyUmnVW774y7h2xyLXg0wdtu25nbU2AvOmyzcWa7JTdCKuuy3CblxueGwqYkQDDQIya1Qny4blyAvh_a1Q28LgzEKBcH7Em9FZXerhkvR9v4FWbCC5AgNLdQ7sR8-rUQdShmJcGDKdVmsZjuO4XhY2Zx0nFnkcvYfsU9bccoAvkKpVJATXzwBqdoEOuFlplnbxsMH1wWbAd3hbcPPWTdvO43xavNZTB5ybgrXVDEYjw8D-98_ZkqxS0vfvhJ4cGefHViaFzp6zXm7msdBpcE__O9rFbdl9Gvup_bsMbrHJioIrmc2d15Yc-tTNTF9J4qjD_lNxMRlx5o2TZEw\")",
+ "success_response_body": "consumerJsonV510",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDirectory, apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(Nil)"
+ }
+ },
+ "createConsumer": {
+ "partial_function_name_raw": "nameOf(createConsumer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Create a Consumer\"",
+ "description": "s\"\"\"Create a Consumer (Authenticated access).\n |\n |A Consumer represents an application that uses the Open Bank Project API. Each Consumer has:\n |- A unique **key** (40 character random string) - used as the client ID for authentication\n |- A unique **secret** (40 character random string) - used for secure authentication\n |- An **app_type** (Confidential or Public) - determines OAuth2 flow requirements\n |- Metadata like app_name, description, developer_email, company, etc.\n |\n |**How it works (for comprehension flow):**\n |\n |1. **Extract authenticated user**: Retrieves the currently logged-in user who is creating the consumer\n |2. **Parse and validate JSON request**: Extracts the CreateConsumerRequestJsonV510 from the request body\n |3. **Determine app_type**: Converts the string \"Confidential\" or \"Public\" to the AppType enum\n |4. **Generate credentials**: Creates random 40-character key and secret for the new consumer\n |5. **Create consumer record**: Calls createConsumerNewStyle with all parameters:\n | - Auto-generated key and secret\n | - enabled flag (controls if consumer is active)\n | - app_name, description, developer_email, company\n | - redirect_url (for OAuth flows)\n | - client_certificate (optional, for certificate-based auth)\n | - logo_url (optional)\n | - createdByUserId (the authenticated user's ID)\n |6. **Return response**: Returns the newly created consumer with HTTP 201 Created status\n |\n |**Client Certificate (Optional but Recommended for PSD2/Berlin Group):**\n |\n |The `client_certificate` field provides enhanced security through X.509 certificate validation.\n |\n |**IMPORTANT SECURITY NOTE:**\n |- **This endpoint does NOT validate the certificate at creation time** - any certificate can be provided\n |- The certificate is simply stored with the consumer record without checking if it's from a trusted CA\n |- For PSD2/Berlin Group compliance with certificate validation, use the **Dynamic Registration** endpoint instead\n |- Dynamic Registration validates certificates against registered Regulated Entities and trusted CAs\n |\n |**How certificates are used (after creation):**\n |- Certificate is stored in PEM format (Base64-encoded X.509) with the consumer record\n |- On subsequent API requests, the certificate from the `PSD2-CERT` header is compared against the stored certificate\n |- If certificates don't match, access is denied even with valid OAuth2 tokens\n |- First request populates the certificate if not set; subsequent requests must match that certificate\n |\n |**Certificate validation process (during API requests, NOT at consumer creation):**\n |1. Certificate from `PSD2-CERT` header is compared to stored certificate (simple string match)\n |2. Certificate is parsed from PEM format to X.509Certificate object\n |3. Validated against a configured trust store (PKCS12 format) containing trusted root CAs\n |4. Certificate chain is verified using PKIX validation\n |5. Optional CRL (Certificate Revocation List) checking if enabled via `use_tpp_signature_revocation_list`\n |6. Public key from certificate can verify signed requests (Berlin Group requirement)\n |\n |**Note:** Steps 3-6 only apply during API request validation, NOT during consumer creation via this endpoint.\n |\n |**Security benefits (when properly configured):**\n |- **Certificate binding**: Links consumer to a specific certificate (prevents token reuse with different certs)\n |- **Request verification**: Certificate's public key can verify signed requests\n |- **Non-repudiation**: Certificate-based signatures prove request origin\n |\n |**Security limitations of this endpoint:**\n |- **No validation at creation**: Any certificate (even self-signed or expired) can be stored\n |- **No CA verification**: Certificate is not checked against trusted root CAs during creation\n |- **No Regulated Entity check**: Does not verify the TPP is registered\n |- **Use Dynamic Registration instead** for proper PSD2/Berlin Group compliance with full certificate validation\n |\n |**For proper PSD2 compliance:**\n |Use the **Dynamic Consumer Registration** endpoint (`POST /obp/v5.1.0/dynamic-registration/consumers`) which:\n |- Requires JWT-signed request using the certificate's private key\n |- Validates certificate against Regulated Entity registry\n |- Checks certificate is from a trusted CA using the configured trust store\n |- Ensures proper QWAC/eIDAS compliance for EU TPPs\n |\n |**Configuration properties (for runtime validation):**\n |- `truststore.path.tpp_signature` - Path to trust store for certificate validation during API requests\n |- `truststore.password.tpp_signature` - Trust store password\n |- `use_tpp_signature_revocation_list` - Enable/disable CRL checking during requests (default: true)\n |- `consumer_validation_method_for_consent` - Set to \"CONSUMER_CERTIFICATE\" for cert-based validation\n |- `bypass_tpp_signature_validation` - Emergency bypass (default: false, use only for testing)\n |\n |**Important**: The key and secret are only shown once in the response. Save them securely as they cannot be retrieved later.\n |\n |${consumerDisabledText()}\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "createConsumerRequestJsonV510",
+ "success_response_body": "consumerJsonOnlyForPostResponseV510",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canCreateConsumer))"
+ }
+ },
+ "createMyConsumer": {
+ "partial_function_name_raw": "nameOf(createMyConsumer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/consumers\"",
+ "summary": "\"Create a Consumer\"",
+ "description": "s\"\"\"Create a Consumer (Authenticated access).\n |\n |\"\"\"",
+ "example_request_body": "createConsumerRequestJsonV510",
+ "success_response_body": "consumerJsonV510",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)"
+ },
+ "getCallsLimit": {
+ "partial_function_name_raw": "nameOf(getCallsLimit)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/rate-limits\"",
+ "summary": "\"Get Rate Limits for a Consumer\"",
+ "description": "s\"\"\"\n |Get Calls limits per Consumer.\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "callLimitsJson510Example",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadCallLimits))"
+ }
+ },
+ "updateConsumerRedirectURL": {
+ "partial_function_name_raw": "nameOf(updateConsumerRedirectURL)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/redirect_url\"",
+ "summary": "\"Update Consumer RedirectURL\"",
+ "description": "s\"\"\"Update an existing redirectUrl for a Consumer specified by CONSUMER_ID.\n |\n | ${consumerDisabledText()}\n |\n | CONSUMER_ID can be obtained after you register the application.\n |\n | Or use the endpoint 'Get Consumers' to get it\n |\n \"\"\".stripMargin",
+ "example_request_body": "consumerRedirectUrlJSON",
+ "success_response_body": "consumerJSON",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsumerRedirectUrl))"
+ }
+ },
+ "updateConsumerLogoURL": {
+ "partial_function_name_raw": "nameOf(updateConsumerLogoURL)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/logo_url\"",
+ "summary": "\"Update Consumer LogoURL\"",
+ "description": "s\"\"\"Update an existing logoURL for a Consumer specified by CONSUMER_ID.\n |\n | ${consumerDisabledText()}\n |\n | CONSUMER_ID can be obtained after you register the application.\n |\n | Or use the endpoint 'Get Consumers' to get it\n |\n \"\"\".stripMargin",
+ "example_request_body": "consumerLogoUrlJson",
+ "success_response_body": "consumerJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsumerLogoUrl))"
+ }
+ },
+ "updateConsumerCertificate": {
+ "partial_function_name_raw": "nameOf(updateConsumerCertificate)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/certificate\"",
+ "summary": "\"Update Consumer Certificate\"",
+ "description": "s\"\"\"Update a Certificate for a Consumer specified by CONSUMER_ID.\n |\n | ${consumerDisabledText()}\n |\n | CONSUMER_ID can be obtained after you register the application.\n |\n | Or use the endpoint 'Get Consumers' to get it\n |\n \"\"\".stripMargin",
+ "example_request_body": "consumerCertificateJson",
+ "success_response_body": "consumerJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsumerCertificate))"
+ }
+ },
+ "updateConsumerName": {
+ "partial_function_name_raw": "nameOf(updateConsumerName)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/name\"",
+ "summary": "\"Update Consumer Name\"",
+ "description": "s\"\"\"Update an existing name for a Consumer specified by CONSUMER_ID.\n |\n | ${consumerDisabledText()}\n |\n | CONSUMER_ID can be obtained after you register the application.\n |\n | Or use the endpoint 'Get Consumers' to get it\n |\n \"\"\".stripMargin",
+ "example_request_body": "consumerNameJson",
+ "success_response_body": "consumerJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateConsumerName))"
+ }
+ },
+ "getConsumer": {
+ "partial_function_name_raw": "nameOf(getConsumer)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Get Consumer\"",
+ "description": "s\"\"\"Get the Consumer specified by CONSUMER_ID.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumerJSON",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ConsumerNotFoundByConsumerId,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "getConsumers": {
+ "partial_function_name_raw": "nameOf(getConsumers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers\"",
+ "summary": "\"Get Consumers\"",
+ "description": "s\"\"\"Get the all Consumers.\n |\n |${userAuthenticationMessage(true)}\n |\n |${urlParametersDocument(true, true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumersJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "grantUserAccessToViewById": {
+ "partial_function_name_raw": "nameOf(grantUserAccessToViewById)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/grant\"",
+ "summary": "\"Grant User access to View\"",
+ "description": "s\"\"\"Grants the User identified by USER_ID access to the view on a bank account identified by VIEW_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |**Permission Requirements:**\n |The requesting user must have access to the source VIEW_ID and must possess specific grant permissions:\n |\n |**For System Views (e.g., owner, accountant, auditor, public etc.):**\n |- The user's current view must have the target view listed in its `canGrantAccessToViews` field\n |- Example: If granting access to \"accountant\" view, the user's view must include \"accountant\" in `canGrantAccessToViews`\n |\n |**For Custom Views (account-specific views):**\n |- The user's current view must have the `can_grant_access_to_custom_views` permission in its `allowed_actions` field\n |- This permission allows granting access to any custom view on the account\n |\n |**Security Checks Performed:**\n |1. User authentication validation\n |2. JSON format validation (USER_ID and VIEW_ID required)\n |3. Permission authorization via `APIUtil.canGrantAccessToView()`\n |4. Target user existence verification\n |5. Target view existence and type validation (system vs custom)\n |6. Final access grant operation in database\n |\n |**Final Database Operation:**\n |The system creates an `AccountAccess` record linking the user to the view if one doesn't already exist.\n |This operation includes:\n |- Duplicate check: Prevents creating duplicate access records (idempotent operation)\n |- Public view restriction: Blocks access to public views if disabled instance-wide\n |- Database constraint validation: Ensures referential integrity\n |\n |**Note:** The permission model ensures users can only delegate access rights they themselves possess or are explicitly authorized to grant.\n |\n |\"\"\"",
+ "example_request_body": "postAccountAccessJsonV510",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,\n UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,\n InvalidJsonFormat,\n UserNotFoundById,\n SystemViewNotFound,\n ViewNotFound,\n CannotGrantAccountAccess,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)"
+ },
+ "revokeUserAccessToViewById": {
+ "partial_function_name_raw": "nameOf(revokeUserAccessToViewById)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/revoke\"",
+ "summary": "\"Revoke User access to View\"",
+ "description": "s\"\"\"Revoke the User identified by USER_ID access to the view identified.\n |\n |${userAuthenticationMessage(true)}.\n |\n |\"\"\"",
+ "example_request_body": "postAccountAccessJsonV510",
+ "success_response_body": "revokedJsonV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount,\n UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount,\n InvalidJsonFormat,\n UserNotFoundById,\n SystemViewNotFound,\n ViewNotFound,\n CannotRevokeAccountAccess,\n CannotFindAccountAccess,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)"
+ },
+ "createUserWithAccountAccessById": {
+ "partial_function_name_raw": "nameOf(createUserWithAccountAccessById)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/user-account-access\"",
+ "summary": "\"Create (DAuth) User with Account Access\"",
+ "description": "s\"\"\"This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain.\n |\n |Put the smart contract address in username\n |\n |For provider use \"dauth\"\n |\n |This endpoint will create the (DAuth) User with username and provider if the User does not already exist.\n |\n |${userAuthenticationMessage(true)} and the logged in user needs to be account holder.\n |\n |For information about DAuth see below:\n |\n |${Glossary.getGlossaryItem(\"DAuth\")}\n |\n |\"\"\"",
+ "example_request_body": "postCreateUserAccountAccessJsonV400",
+ "success_response_body": "List(viewJsonV300)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,\n UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,\n InvalidJsonFormat,\n SystemViewNotFound,\n ViewNotFound,\n CannotGrantAccountAccess,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired, apiTagDAuth)"
+ },
+ "getTransactionRequestById": {
+ "partial_function_name_raw": "nameOf(getTransactionRequestById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/transaction-requests/TRANSACTION_REQUEST_ID\"",
+ "summary": "\"Get Transaction Request by ID.\"",
+ "description": "\"\"\"Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestWithChargeJSON210",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n GetTransactionRequestsException,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetTransactionRequestAtOneBank, canGetTransactionRequestAtAnyBank))"
+ }
+ },
+ "getTransactionRequests": {
+ "partial_function_name_raw": "nameOf(getTransactionRequests)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests\"",
+ "summary": "\"Get Transaction Requests.\"",
+ "description": "\"\"\"Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.\n |\n |The VIEW_ID specified must be 'owner' and the user must have access to this view.\n |\n |Version 2.0.0 now returns charge information.\n |\n |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including:\n |\n |* Transaction Request Id\n |* Type\n |* Status (INITIATED, COMPLETED)\n |* Challenge (in order to confirm the request)\n |* From Bank / Account\n |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.)\n |* Related Transactions\n |\n |PSD2 Context: PSD2 requires transparency of charges to the customer.\n |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after.\n |The customer can proceed with the Transaction by answering the security challenge.\n |\n |We support query transaction request by attribute\n |URL params example:/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests?invoiceNumber=123&referenceNumber=456\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "transactionRequestWithChargeJSONs210",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n BankNotFound,\n BankAccountNotFound,\n UserNoPermissionAccessView,\n ViewDoesNotPermitAccess,\n GetTransactionRequestsException,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS)"
+ },
+ "updateTransactionRequestStatus": {
+ "partial_function_name_raw": "nameOf(updateTransactionRequestStatus)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/transaction-requests/TRANSACTION_REQUEST_ID\"",
+ "summary": "\"Update Transaction Request Status\"",
+ "description": "s\"\"\" Update Transaction Request Status\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PostTransactionRequestStatusJsonV510(TransactionRequestStatus.COMPLETED.toString)",
+ "success_response_body": "PostTransactionRequestStatusJsonV510(TransactionRequestStatus.COMPLETED.toString)",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateTransactionRequestStatusAtOneBank, canUpdateTransactionRequestStatusAtAnyBank))"
+ }
+ },
+ "getAccountAccessByUserId": {
+ "partial_function_name_raw": "nameOf(getAccountAccessByUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/account-access\"",
+ "summary": "\"Get Account Access by USER_ID\"",
+ "description": "s\"\"\"Get Account Access by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountsMinimalJson400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canSeeAccountAccessForAnyUser))"
+ }
+ },
+ "getApiTags": {
+ "partial_function_name_raw": "nameOf(getApiTags)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/tags\"",
+ "summary": "\"Get API Tags\"",
+ "description": "s\"\"\"Get API TagsGet API Tags\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountsMinimalJson400",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi)"
+ },
+ "getCoreAccountByIdThroughView": {
+ "partial_function_name_raw": "nameOf(getCoreAccountByIdThroughView)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Get Account by Id (Core) through the VIEW_ID\"",
+ "description": "s\"\"\"Information returned about the account through VIEW_ID :\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountJsonV400",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, $BankAccountNotFound,UnknownError)",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBankAccountBalances": {
+ "partial_function_name_raw": "nameOf(getBankAccountBalances)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/balances\"",
+ "summary": "\"Get Account Balances by BANK_ID and ACCOUNT_ID through the VIEW_ID\"",
+ "description": "\"\"\"Get the Balances for the Account specified by BANK_ID and ACCOUNT_ID through the VIEW_ID.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalanceV400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBankAccountsBalances": {
+ "partial_function_name_raw": "nameOf(getBankAccountsBalances)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/balances\"",
+ "summary": "\"Get Account Balances by BANK_ID\"",
+ "description": "\"\"\"Get the Balances for the Account specified by BANK_ID.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalancesV400Json",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBankAccountsBalancesThroughView": {
+ "partial_function_name_raw": "nameOf(getBankAccountsBalancesThroughView)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/views/VIEW_ID/balances\"",
+ "summary": "\"Get Account Balances by BANK_ID through the VIEW_ID\"",
+ "description": "\"\"\"Get the Balances for the Account specified by BANK_ID.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "accountBalancesV400Json",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "createCounterpartyLimit": {
+ "partial_function_name_raw": "nameOf(createCounterpartyLimit)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits\"",
+ "summary": "\"Create Counterparty Limit\"",
+ "description": "s\"\"\"Create limits (for single or recurring payments) for a counterparty specified by the COUNTERPARTY_ID.\n |\n |Using this endpoint, we can attach a limit record to a Counterparty referenced by its counterparty_id (a UUID).\n |\n |For more information on Counterparty Limits, see ${Glossary.getGlossaryItemLink(\"Counterparty-Limits\")}\n |\n |For an introduction to Counterparties in OBP, see ${Glossary.getGlossaryItemLink(\"Counterparties\")}\n |\n |You can automate the process of creating counterparty limits and consents for VRP with this ${Glossary.getApiExplorerLink(\"endpoint\", \"OBPv5.1.0-createVRPConsentRequest\")}.\n |\n |\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postCounterpartyLimitV510",
+ "success_response_body": "counterpartyLimitV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n $CounterpartyNotFoundByCounterpartyId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyLimits)"
+ },
+ "updateCounterpartyLimit": {
+ "partial_function_name_raw": "nameOf(updateCounterpartyLimit)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits\"",
+ "summary": "\"Update Counterparty Limit\"",
+ "description": "s\"\"\"Update Counterparty Limit.\"\"\"",
+ "example_request_body": "postCounterpartyLimitV510",
+ "success_response_body": "counterpartyLimitV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n $CounterpartyNotFoundByCounterpartyId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyLimits)"
+ },
+ "getCounterpartyLimit": {
+ "partial_function_name_raw": "nameOf(getCounterpartyLimit)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits\"",
+ "summary": "\"Get Counterparty Limit\"",
+ "description": "s\"\"\"Get Counterparty Limit.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyLimitV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n $CounterpartyNotFoundByCounterpartyId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyLimits)"
+ },
+ "getCounterpartyLimitStatus": {
+ "partial_function_name_raw": "nameOf(getCounterpartyLimitStatus)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limit-status\"",
+ "summary": "\"Get Counterparty Limit Status\"",
+ "description": "s\"\"\"Get Counterparty Limit Status.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyLimitStatusV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n $CounterpartyNotFoundByCounterpartyId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyLimits)"
+ },
+ "deleteCounterpartyLimit": {
+ "partial_function_name_raw": "nameOf(deleteCounterpartyLimit)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits\"",
+ "summary": "\"Delete Counterparty Limit\"",
+ "description": "s\"\"\"Delete Counterparty Limit.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n $CounterpartyNotFoundByCounterpartyId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagCounterpartyLimits)"
+ },
+ "createCustomView": {
+ "partial_function_name_raw": "nameOf(createCustomView)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views\"",
+ "summary": "\"Create Custom View\"",
+ "description": "s\"\"\"Create a custom view on bank account\n |\n | ${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n | The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n | You MUST use a leading _ (underscore) in the view name because other view names are reserved for OBP [system views](/index#group-View-System).\n | \"\"\"",
+ "example_request_body": "createCustomViewJson",
+ "success_response_body": "customViewJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "updateCustomView": {
+ "partial_function_name_raw": "nameOf(updateCustomView)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID\"",
+ "summary": "\"Update Custom View\"",
+ "description": "s\"\"\"Update an existing custom view on a bank account\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\n |\n |The json sent is the same as during view creation (above), with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created)\"\"\"",
+ "example_request_body": "updateCustomViewJson",
+ "success_response_body": "customViewJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "getCustomView": {
+ "partial_function_name_raw": "nameOf(getCustomView)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID\"",
+ "summary": "\"Get Custom View\"",
+ "description": "s\"\"\"#Views\n |\n |\n |Views in Open Bank Project provide a mechanism for fine grained access control and delegation to Accounts and Transactions. Account holders use the 'owner' view by default. Delegated access is made through other views for example 'accountants', 'share-holders' or 'tagging-application'. Views can be created via the API and each view has a list of entitlements.\n |\n |Views on accounts and transactions filter the underlying data to redact certain fields for certain users. For instance the balance on an account may be hidden from the public. The way to know what is possible on a view is determined in the following JSON.\n |\n |**Data:** When a view moderates a set of data, some fields my contain the value `null` rather than the original value. This indicates either that the user is not allowed to see the original data or the field is empty.\n |\n |There is currently one exception to this rule; the 'holder' field in the JSON contains always a value which is either an alias or the real name - indicated by the 'is_alias' field.\n |\n |**Action:** When a user performs an action like trying to post a comment (with POST API call), if he is not allowed, the body response will contain an error message.\n |\n |**Metadata:**\n |Transaction metadata (like images, tags, comments, etc.) will appears *ONLY* on the view where they have been created e.g. comments posted to the public view only appear on the public view.\n |\n |The other account metadata fields (like image_URL, more_info, etc.) are unique through all the views. Example, if a user edits the 'more_info' field in the 'team' view, then the view 'authorities' will show the new value (if it is allowed to do it).\n |\n |# All\n |*Optional*\n |\n |Returns the list of the views created for account ACCOUNT_ID at BANK_ID.\n |\n |${userAuthenticationMessage(true)} and the user needs to have access to the owner view.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customViewJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "deleteCustomView": {
+ "partial_function_name_raw": "nameOf(deleteCustomView)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/target-views/TARGET_VIEW_ID\"",
+ "summary": "\"Delete Custom View\"",
+ "description": "\"Deletes the custom view specified by VIEW_ID on the bank account specified by ACCOUNT_ID at bank BANK_ID\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "createVRPConsentRequest": {
+ "partial_function_name_raw": "nameOf(createVRPConsentRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/consumer/vrp-consent-requests\"",
+ "summary": "\"Create Consent Request VRP\"",
+ "description": "s\"\"\"\n |This endpoint is used to begin the process of creating a consent that may be used for Variable Recurring Payments (VRPs).\n |\n |VRPs are useful in situations when a beneficiary needs to be paid different amounts on a regular basis.\n |\n |Once granted, the consent allows its holder to initiate multiple Transaction Requests to the Counterparty defined in this endpoint as long as the\n |Counterparty Limits linked to this particular consent are respected.\n |\n |Client, Consumer or Application Authentication is mandatory for this endpoint.\n |\n |i.e. the caller of this endpoint is the API Client, Consumer or Application rather than a specific User.\n |\n |At the end of the process the following objects are created in OBP or connected backend systems:\n | - An automatically generated View which controls access.\n | - A Counterparty that is the Beneficiary of the Variable Recurring Payments. The Counterparty specifies the Bank Account number or other routing address.\n | - Limits for the Counterparty which constrain the amount of money that can be sent to it in various periods (yearly, monthly, weekly).\n |\n |The Account holder may modify the Counterparty or Limits e.g. to increase or decrease the maximum possible payment amounts or the frequencey of the payments.\n |\n |\n |In the case of a public client we use the client_id and private key to obtain an access token, otherwise we use the client_id and client_secret.\n |The obtained access token is used in the HTTP Authorization header of the request as follows:\n |\n |Example:\n |Authorization: Bearer eXtneO-THbQtn3zvK_kQtXXfvOZyZFdBCItlPDbR2Bk.dOWqtXCtFX-tqGTVR0YrIjvAolPIVg7GZ-jz83y6nA0\n |\n |After successfully creating the VRP consent request, you need to call the `Create Consent By CONSENT_REQUEST_ID` endpoint to finalize the consent using the CONSENT_REQUEST_ID returned by this endpoint.\n |\n |${applicationAccessMessage(true)}\n |\n |${userAuthenticationMessage(false)}\n |\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postVRPConsentRequestJsonV510",
+ "success_response_body": "vrpConsentRequestResponseJson",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n ConsentMaxTTL,\n X509CannotGetCertificate,\n X509GeneralError,\n InvalidConnectorResponse,\n UnknownError\n )",
+ "tags": "apiTagConsent :: apiTagVrp :: apiTagTransactionRequest :: Nil"
+ },
+ "createRegulatedEntityAttribute": {
+ "partial_function_name_raw": "nameOf(createRegulatedEntityAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID/attributes\"",
+ "summary": "\"Create Regulated Entity Attribute\"",
+ "description": "s\"\"\"\n | Create a new Regulated Entity Attribute for a given REGULATED_ENTITY_ID.\n |\n | The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or \"DATE_WITH_DAY\".\n | ${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "regulatedEntityAttributeRequestJsonV510",
+ "success_response_body": "regulatedEntityAttributeResponseJsonV510",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError)",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateRegulatedEntityAttribute))"
+ }
+ },
+ "deleteRegulatedEntityAttribute": {
+ "partial_function_name_raw": "nameOf(deleteRegulatedEntityAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Regulated Entity Attribute\"",
+ "description": "s\"\"\"\n | Delete a Regulated Entity Attribute specified by REGULATED_ENTITY_ATTRIBUTE_ID.\n |\n | ${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteRegulatedEntityAttribute))"
+ }
+ },
+ "getRegulatedEntityAttributeById": {
+ "partial_function_name_raw": "nameOf(getRegulatedEntityAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID\"",
+ "summary": "\"Get Regulated Entity Attribute By ID\"",
+ "description": "s\"\"\"\n | Get a specific Regulated Entity Attribute by its REGULATED_ENTITY_ATTRIBUTE_ID.\n |\n | ${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "regulatedEntityAttributeResponseJsonV510",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired,UnknownError)",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRegulatedEntityAttribute))"
+ }
+ },
+ "getAllRegulatedEntityAttributes": {
+ "partial_function_name_raw": "nameOf(getAllRegulatedEntityAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID/attributes\"",
+ "summary": "\"Get All Regulated Entity Attributes\"",
+ "description": "s\"\"\"\n | Get all attributes for the specified Regulated Entity.\n |\n | ${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "regulatedEntityAttributesJsonV510",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRegulatedEntityAttributes))"
+ }
+ },
+ "updateRegulatedEntityAttribute": {
+ "partial_function_name_raw": "nameOf(updateRegulatedEntityAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/regulated-entities/REGULATED_ENTITY_ID/attributes/REGULATED_ENTITY_ATTRIBUTE_ID\"",
+ "summary": "\"Update Regulated Entity Attribute\"",
+ "description": "s\"\"\"\n | Update an existing Regulated Entity Attribute specified by ATTRIBUTE_ID.\n |\n | ${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "regulatedEntityAttributeRequestJsonV510",
+ "success_response_body": "regulatedEntityAttributeResponseJsonV510",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError)",
+ "tags": "List(apiTagDirectory, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateRegulatedEntityAttribute))"
+ }
+ },
+ "createBankAccountBalance": {
+ "partial_function_name_raw": "nameOf(createBankAccountBalance)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances\"",
+ "summary": "\"Create Bank Account Balance\"",
+ "description": "s\"\"\"Create a new Balance for a Bank Account.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "bankAccountBalanceRequestJsonV510",
+ "success_response_body": "bankAccountBalanceResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagBalance)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankAccountBalance))"
+ }
+ },
+ "getBankAccountBalanceById": {
+ "partial_function_name_raw": "nameOf(getBankAccountBalanceById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID\"",
+ "summary": "\"Get Bank Account Balance By ID\"",
+ "description": "s\"\"\"Get a specific Bank Account Balance by its BALANCE_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankAccountBalanceResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagBalance)"
+ },
+ "getAllBankAccountBalances": {
+ "partial_function_name_raw": "nameOf(getAllBankAccountBalances)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances\"",
+ "summary": "\"Get All Bank Account Balances\"",
+ "description": "s\"\"\"Get all Balances for a Bank Account.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "bankAccountBalancesJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagBalance)"
+ },
+ "updateBankAccountBalance": {
+ "partial_function_name_raw": "nameOf(updateBankAccountBalance)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID\"",
+ "summary": "\"Update Bank Account Balance\"",
+ "description": "s\"\"\"Update an existing Bank Account Balance specified by BALANCE_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "bankAccountBalanceRequestJsonV510",
+ "success_response_body": "bankAccountBalanceResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagBalance)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankAccountBalance))"
+ }
+ },
+ "deleteBankAccountBalance": {
+ "partial_function_name_raw": "nameOf(deleteBankAccountBalance)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/balances/BALANCE_ID\"",
+ "summary": "\"Delete Bank Account Balance\"",
+ "description": "s\"\"\"Delete a Bank Account Balance specified by BALANCE_ID.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagBalance)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankAccountBalance))"
+ }
+ },
+ "getWebUiProps": {
+ "partial_function_name_raw": "nameOf(getWebUiProps)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/webui-props\"",
+ "summary": "\"Get WebUiProps\"",
+ "description": "s\"\"\"\n |\n |Get the all WebUiProps key values, those props key with \"webui_\" can be stored in DB, this endpoint get all from DB.\n |\n |url query parameter:\n |active: It must be a boolean string. and If active = true, it will show\n | combination of explicit (inserted) + implicit (default) method_routings.\n |\n |eg:\n |${getObpApiRoot}/v5.1.0/webui-props\n |${getObpApiRoot}/v5.1.0/webui-props?active=true\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"webui-props\",\n (List(WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"web-ui-props-id\"))))\n )",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)"
+ },
+ "addSystemViewPermission": {
+ "partial_function_name_raw": "nameOf(addSystemViewPermission)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/system-views/VIEW_ID/permissions\"",
+ "summary": "\"Add Permission to a System View\"",
+ "description": "\"\"\"Add Permission to a System View.\"\"\"",
+ "example_request_body": "createViewPermissionJson",
+ "success_response_body": "entitlementJSON",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n IncorrectRoleName,\n EntitlementAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSystemViewPermission))"
+ }
+ },
+ "deleteSystemViewPermission": {
+ "partial_function_name_raw": "nameOf(deleteSystemViewPermission)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/system-views/VIEW_ID/permissions/PERMISSION_NAME\"",
+ "summary": "\"Delete Permission to a System View\"",
+ "description": "\"\"\"Delete Permission to a System View\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemViewPermission))"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/lift_resource_docs_v6_0_0.json b/scripts/resource_doc_baseline/lift_resource_docs_v6_0_0.json
new file mode 100644
index 0000000000..c4d9d185e0
--- /dev/null
+++ b/scripts/resource_doc_baseline/lift_resource_docs_v6_0_0.json
@@ -0,0 +1,3320 @@
+{
+ "schema_version": 1,
+ "version": "v6_0_0",
+ "source_file": "obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala",
+ "exported_from_git_commit": "e198c922328095b9abbd1370056fb5ee002f7980",
+ "endpoint_count": 243,
+ "endpoints": {
+ "root": {
+ "partial_function_name_raw": "nameOf(root)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/root\"",
+ "summary": "\"Get API Info (root)\"",
+ "description": "\"\"\"Returns information about:\n |\n |* API version\n |* Hosted by information\n |* Hosted at information\n |* Energy source information\n |* Git Commit\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiInfoJson400",
+ "error_response_bodies": "List(UnknownError, MandatoryPropertyIsNotSet)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "getFeatures": {
+ "partial_function_name_raw": "nameOf(getFeatures)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/features\"",
+ "summary": "\"Get Features\"",
+ "description": "\"\"\"Returns information about the features enabled on this OBP instance.\n |\n |No Authentication is Required.\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "featuresJsonV600",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagApi :: Nil"
+ },
+ "createTransactionRequestHold": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestHold)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/HOLD/transaction-requests\"",
+ "summary": "\"Create Transaction Request (HOLD)\"",
+ "description": "s\"\"\"\n |\n |Create a transaction request to move funds from the account to its Holding Account.\n |If the Holding Account does not exist, it will be created automatically.\n |\n |${transactionRequestGeneralText}\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyHoldJsonV600",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "getHoldingAccountByReleaser": {
+ "partial_function_name_raw": "nameOf(getHoldingAccountByReleaser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/holding-accounts\"",
+ "summary": "\"Get Holding Accounts By Releaser\"",
+ "description": "s\"\"\"\n |\n |Return the first Holding Account linked to the given releaser account via account attribute `RELEASER_ACCOUNT_ID`.\n |Response is wrapped in a list and includes account attributes.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "moderatedCoreAccountsJsonV300",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)"
+ },
+ "getAccountsAtBank": {
+ "partial_function_name_raw": "nameOf(getAccountsAtBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts\"",
+ "summary": "\"Get Accounts at Bank\"",
+ "description": "s\"\"\"\n |Returns the list of accounts at BANK_ID that the user has access to.\n |For each account the API returns the account ID and the views available to the user.\n |Each account must have at least one private View.\n |\n |This v6.0.0 version returns `account_id` instead of `id` for consistency with other v6.0.0 endpoints.\n |\n |Optional request parameters for filtering with attributes:\n |URL params example: /banks/some-bank-id/accounts?limit=50&offset=1\n |\n |${userAuthenticationMessage(true)}\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BasicAccountsJsonV600(List(BasicAccountJsonV600(\n account_id = \"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n bank_id = \"gh.29.uk\",\n label = \"My Account\",\n views_available = List(BasicViewJson(\"owner\", \"Owner\", false))\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagPrivateData, apiTagPublicData)"
+ },
+ "getCoreAccountByIdV600": {
+ "partial_function_name_raw": "nameOf(getCoreAccountByIdV600)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/banks/BANK_ID/accounts/ACCOUNT_ID/account\"",
+ "summary": "\"Get Account by Id (Core)\"",
+ "description": "s\"\"\"Information returned about the account specified by ACCOUNT_ID:\n |\n |* Number - The human readable account number given by the bank that identifies the account.\n |* Label - A label given by the owner of the account\n |* Owners - Users that own this account\n |* Type - The type of account\n |* Balance - Currency and Value\n |* Account Routings - A list that might include IBAN or national account identifiers\n |* Account Rules - A list that might include Overdraft and other bank specific rules\n |* Tags - A list of Tags assigned to this account\n |\n |This call returns the owner view and requires access to that view.\n |\n |This v6.0.0 version returns `account_id` instead of `id` for consistency with other v6.0.0 endpoints.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ModeratedCoreAccountJsonV600(\n account_id = \"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\",\n bank_id = \"gh.29.uk\",\n label = \"My Account\",\n number = \"123456\",\n product_code = \"CURRENT\",\n balance = AmountOfMoneyJsonV121(\"EUR\", \"1000.00\"),\n account_routings = List(AccountRoutingJsonV121(\"IBAN\", \"DE89370400440532013000\")),\n views_basic = List(\"owner\")\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankAccountNotFound,\n UnknownError\n )",
+ "tags": "apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getConsumerCallCounters": {
+ "partial_function_name_raw": "nameOf(getConsumerCallCounters)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/call-counters\"",
+ "summary": "\"Get Call Counts for Consumer\"",
+ "description": "s\"\"\"\n |Get the call counters (current usage) for a specific consumer. Shows how many API calls have been made and when the counters reset.\n |\n |This endpoint returns the current state of API rate limits across all time periods (per second, per minute, per hour, per day, per week, per month).\n |\n |**Response Structure:**\n |The response always contains a consistent structure with all six time periods, regardless of whether rate limits are configured or active.\n |\n |Each time period contains:\n |- `calls_made`: Number of API calls made in the current period (null if no data available)\n |- `reset_in_seconds`: Seconds until the counter resets (null if no data available)\n |- `status`: Current state of the rate limit for this period\n |\n |**Status Values:**\n |- `ACTIVE`: Rate limit counter is active and tracking calls. Both `calls_made` and `reset_in_seconds` will have numeric values.\n |- `NO_COUNTER`: Key does not exist - the consumer has not made any API calls in this time period yet.\n |- `EXPIRED`: The rate limit counter has expired (TTL reached 0). The counter will be recreated on the next API call.\n |- `REDIS_UNAVAILABLE`: Cannot retrieve data from Redis. This indicates a system connectivity issue.\n |- `DATA_MISSING`: Unexpected error - period data is missing from the response. This should not occur under normal circumstances.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "redisCallCountersJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRateLimits))"
+ }
+ },
+ "createCallLimits": {
+ "partial_function_name_raw": "nameOf(createCallLimits)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/rate-limits\"",
+ "summary": "\"Create Rate Limits for a Consumer\"",
+ "description": "s\"\"\"\n |Create Rate Limits for a Consumer\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "callLimitPostJsonV600",
+ "success_response_body": "callLimitJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateRateLimits))"
+ }
+ },
+ "updateRateLimits": {
+ "partial_function_name_raw": "nameOf(updateRateLimits)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/rate-limits/RATE_LIMITING_ID\"",
+ "summary": "\"Set Rate Limits / Call Limits per Consumer\"",
+ "description": "s\"\"\"\n |Set the API rate limits / call limits for a Consumer:\n |\n |Rate limiting can be set:\n |\n |Per Second\n |Per Minute\n |Per Hour\n |Per Week\n |Per Month\n |\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "callLimitPostJsonV400",
+ "success_response_body": "callLimitPostJsonV400",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UpdateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer, apiTagRateLimits)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateRateLimits))"
+ }
+ },
+ "deleteCallLimits": {
+ "partial_function_name_raw": "nameOf(deleteCallLimits)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/consumer/rate-limits/RATE_LIMITING_ID\"",
+ "summary": "\"Delete Rate Limit by Rate Limiting ID\"",
+ "description": "s\"\"\"\n |Delete a specific Rate Limit by Rate Limiting ID\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteRateLimits))"
+ }
+ },
+ "getActiveRateLimitsAtDate": {
+ "partial_function_name_raw": "nameOf(getActiveRateLimitsAtDate)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/active-rate-limits/DATE_WITH_HOUR\"",
+ "summary": "\"Get Active Rate Limits for Hour\"",
+ "description": "s\"\"\"\n |Get the active rate limits for a consumer for a specific hour. Returns the aggregated rate limits from all active records during that hour.\n |\n |Rate limits are cached and queried at hour-level granularity.\n |\n |See ${Glossary.getGlossaryItemLink(\"Rate Limiting\")} for more details on how rate limiting works.\n |\n |Date format: YYYY-MM-DD-HH in UTC timezone (e.g. 2025-12-31-13 for hour 13:00-13:59 UTC on Dec 31, 2025)\n |\n |Note: The hour is always interpreted in UTC for consistency across all servers.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "activeRateLimitsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n InvalidDateFormat,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRateLimits))"
+ }
+ },
+ "getActiveRateLimitsNow": {
+ "partial_function_name_raw": "nameOf(getActiveRateLimitsNow)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID/active-rate-limits\"",
+ "summary": "\"Get Active Rate Limits (Current)\"",
+ "description": "s\"\"\"\n |Get the active rate limits for a consumer at the current date/time. Returns the aggregated rate limits from all active records at this moment.\n |\n |This is a convenience endpoint that uses the current date/time automatically.\n |\n |See ${Glossary.getGlossaryItemLink(\"Rate Limiting\")} for more details on how rate limiting works.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "activeRateLimitsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidConsumerId,\n ConsumerNotFoundByConsumerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRateLimits))"
+ }
+ },
+ "getCurrentConsumer": {
+ "partial_function_name_raw": "nameOf(getCurrentConsumer)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/consumers/current\"",
+ "summary": "\"Get Current Consumer\"",
+ "description": "s\"\"\"Returns the consumer_id of the current authenticated consumer.\n |\n |This endpoint requires authentication via:\n |* User authentication (OAuth, DirectLogin, etc.) - returns the consumer associated with the user's session\n |* Consumer/Client authentication - returns the consumer credentials being used\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CurrentConsumerJsonV600(\n app_name = \"SOFI\",\n app_type = \"Web\",\n description = \"Account Management\",\n consumer_id = \"123\",\n active_rate_limits = activeRateLimitsJsonV600,\n call_counters = redisCallCountersJsonV600\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidConsumerCredentials,\n UnknownError\n )",
+ "tags": "apiTagConsumer :: apiTagApi :: Nil",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCurrentConsumer))"
+ }
+ },
+ "getConsumer": {
+ "partial_function_name_raw": "nameOf(getConsumer)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/consumers/CONSUMER_ID\"",
+ "summary": "\"Get Consumer\"",
+ "description": "s\"\"\"Get the Consumer specified by CONSUMER_ID.\n |\n |This endpoint returns all consumer fields including:\n |- Basic info: consumer_id, app_name, app_type, description, developer_email, company\n |- OAuth: consumer_key, redirect_url\n |- Status: enabled, created\n |- Certificate: certificate_pem, certificate_info (subject, issuer, validity dates, PSD2 roles)\n |- Branding: logo_url\n |- Creator: created_by_user details\n |- Rate limits: active_rate_limits showing current rate limiting configuration\n |- Call counters: call_counters showing current API call usage from Redis\n |\n |Note: consumer_secret is never returned for security reasons.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "consumerJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ConsumerNotFoundByConsumerId,\n UnknownError\n )",
+ "tags": "List(apiTagConsumer)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canGetConsumers))"
+ }
+ },
+ "invalidateCacheNamespace": {
+ "partial_function_name_raw": "nameOf(invalidateCacheNamespace)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/cache/namespaces/invalidate\"",
+ "summary": "\"Invalidate Cache Namespace\"",
+ "description": "\"\"\"Invalidates a cache namespace by incrementing its version counter.\n |\n |This provides instant cache invalidation without deleting individual keys.\n |Incrementing the version counter makes all keys with the old version unreachable.\n |\n |Available namespace IDs: call_counter, rl_active, rd_localised, rd_dynamic,\n |rd_static, rd_all, swagger_static, connector, metrics_stable, metrics_recent, abac_rule\n |\n |Use after updating rate limits, translations, endpoints, or CBS data.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "InvalidateCacheNamespaceJsonV600(namespace_id = \"rd_localised\")",
+ "success_response_body": "InvalidatedCacheNamespaceJsonV600(\n namespace_id = \"rd_localised\",\n old_version = 1,\n new_version = 2,\n status = \"invalidated\"\n )",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCache, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canInvalidateCacheNamespace))"
+ }
+ },
+ "getCacheConfig": {
+ "partial_function_name_raw": "nameOf(getCacheConfig)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/cache/config\"",
+ "summary": "\"Get Cache Configuration\"",
+ "description": "\"\"\"Returns cache configuration information including:\n |\n |- Redis status: availability, connection details (URL, port, SSL)\n |- In-memory cache status: availability and current size\n |- Instance ID and environment\n |- Global cache namespace prefix\n |\n |This helps understand what cache backend is being used and how it's configured.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CacheConfigJsonV600(\n redis_status = RedisCacheStatusJsonV600(\n available = true,\n url = \"127.0.0.1\",\n port = 6379,\n use_ssl = false\n ),\n in_memory_status = InMemoryCacheStatusJsonV600(\n available = true,\n current_size = 42\n ),\n instance_id = \"obp\",\n environment = \"dev\",\n global_prefix = \"obp_dev_\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCache, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCacheConfig))"
+ }
+ },
+ "getCacheInfo": {
+ "partial_function_name_raw": "nameOf(getCacheInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/cache/info\"",
+ "summary": "\"Get Cache Information\"",
+ "description": "\"\"\"Returns detailed cache information for all namespaces:\n |\n |- Namespace ID and versioned prefix\n |- Current version counter\n |- Number of keys in each namespace\n |- Description and category\n |- Storage location (redis, memory, both, or unknown)\n | - \"redis\": Keys stored in Redis\n | - \"memory\": Keys stored in in-memory cache\n | - \"both\": Keys in both locations (indicates a BUG - should never happen)\n | - \"unknown\": No keys found, storage location cannot be determined\n |- TTL info: Sampled TTL information from actual keys\n | - Shows actual TTL values from up to 5 sample keys\n | - Format: \"123s\" (fixed), \"range 60s to 3600s (avg 1800s)\" (variable), \"no expiry\" (persistent)\n |- Total key count across all namespaces\n |- Redis availability status\n |\n |This endpoint helps monitor cache usage and identify which namespaces contain the most data.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CacheInfoJsonV600(\n namespaces = List(\n CacheNamespaceInfoJsonV600(\n namespace_id = \"call_counter\",\n prefix = \"obp_dev_call_counter_1_\",\n current_version = 1,\n key_count = 42,\n description = \"Rate limit call counters\",\n category = \"Rate Limiting\",\n storage_location = \"redis\",\n ttl_info = \"range 60s to 86400s (avg 3600s)\"\n ),\n CacheNamespaceInfoJsonV600(\n namespace_id = \"rd_localised\",\n prefix = \"obp_dev_rd_localised_1_\",\n current_version = 1,\n key_count = 128,\n description = \"Localized resource docs\",\n category = \"API Documentation\",\n storage_location = \"redis\",\n ttl_info = \"3600s\"\n )\n ),\n total_keys = 170,\n redis_available = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCache, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCacheInfo))"
+ }
+ },
+ "getDatabasePoolInfo": {
+ "partial_function_name_raw": "nameOf(getDatabasePoolInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/database/pool\"",
+ "summary": "\"Get Database Pool Information\"",
+ "description": "\"\"\"Returns HikariCP connection pool information including:\n |\n |- Pool name\n |- Active connections: currently in use\n |- Idle connections: available in pool\n |- Total connections: active + idle\n |- Threads awaiting connection: requests waiting for a connection\n |- Configuration: max pool size, min idle, timeouts\n |\n |This helps diagnose connection pool issues such as connection leaks or pool exhaustion.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DatabasePoolInfoJsonV600(\n pool_name = \"HikariPool-1\",\n active_connections = 5,\n idle_connections = 3,\n total_connections = 8,\n threads_awaiting_connection = 0,\n maximum_pool_size = 10,\n minimum_idle = 2,\n connection_timeout_ms = 30000,\n idle_timeout_ms = 600000,\n max_lifetime_ms = 1800000,\n keepalive_time_ms = 0\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDatabasePoolInfo))"
+ }
+ },
+ "getStoredProcedureConnectorHealth": {
+ "partial_function_name_raw": "nameOf(getStoredProcedureConnectorHealth)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/connectors/stored_procedure_vDec2019/health\"",
+ "summary": "\"Get Stored Procedure Connector Health\"",
+ "description": "\"\"\"Returns health status of the stored procedure connector including:\n |\n |- Connection status (ok/error)\n |- Database server name: identifies which backend node handled the request (useful for load balancer diagnostics)\n |- Server IP address\n |- Database name\n |- Response time in milliseconds\n |- Error message (if any)\n |\n |Supports database-specific queries for: SQL Server, PostgreSQL, Oracle, and MySQL/MariaDB.\n |\n |This endpoint is useful for diagnosing connectivity issues, especially when the database is behind a load balancer\n |and you need to identify which node is responding or experiencing SSL certificate issues.\n |\n |Note: This endpoint may take a long time to respond if the database connection is slow or experiencing issues.\n |The response time depends on the connection pool timeout and JDBC driver settings.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "StoredProcedureConnectorHealthJsonV600(\n status = \"ok\",\n server_name = Some(\"DBSERVER01\"),\n server_ip = Some(\"10.0.1.50\"),\n database_name = Some(\"obp_adapter\"),\n response_time_ms = 45,\n error_message = None\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConnector, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConnectorHealth))"
+ }
+ },
+ "getBanks": {
+ "partial_function_name_raw": "nameOf(getBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Get Banks\"",
+ "description": "\"\"\"Get banks on this API instance\n |Returns a list of banks supported on this server:\n |\n |- bank_id used as parameter in URLs\n |- Short and full name of bank\n |- Logo URL\n |- Website\n |\n |User Authentication is Optional. The User need not be logged in.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BanksJsonV600(List(BankJsonV600(\n bank_id = \"gh.29.uk\",\n bank_code = \"bank_code\",\n full_name = \"full_name\",\n logo = \"logo\",\n website = \"www.openbankproject.com\",\n bank_routings = List(BankRoutingJsonV121(\"OBP\", \"gh.29.uk\")),\n attributes = Some(List(BankAttributeBankResponseJsonV400(\"OVERDRAFT_LIMIT\", \"1000\")))\n )))",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getBank": {
+ "partial_function_name_raw": "nameOf(getBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID\"",
+ "summary": "\"Get Bank\"",
+ "description": "\"\"\"Get the bank specified by BANK_ID\n |Returns information about a single bank specified by BANK_ID including:\n |\n |- bank_id: The unique identifier of this bank\n |- Short and full name of bank\n |- Logo URL\n |- Website\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BankJsonV600(\n bank_id = \"gh.29.uk\",\n bank_code = \"bank_code\",\n full_name = \"full_name\",\n logo = \"logo\",\n website = \"www.openbankproject.com\",\n bank_routings = List(BankRoutingJsonV121(\"OBP\", \"gh.29.uk\")),\n attributes = Some(List(BankAttributeBankResponseJsonV400(\"OVERDRAFT_LIMIT\", \"1000\")))\n )",
+ "error_response_bodies": "List(UnknownError, BankNotFound)",
+ "tags": "apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil"
+ },
+ "getTransactionsForBankAccount": {
+ "partial_function_name_raw": "nameOf(getTransactionsForBankAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions\"",
+ "summary": "\"Get Transactions for Account (Full)\"",
+ "description": "s\"\"\"Returns transactions list of the account specified by ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID).\n |\n |${userAuthenticationMessage(false)}\n |\n |Authentication is required if the view is not public.\n |\n |${urlParametersDocument(true, true)}\n |\n |**Note:** This v6.0.0 endpoint returns `bank_id` directly in both `this_account` and `other_account` objects,\n |making it easier to identify which bank each account belongs to without parsing the `bank_routing` object.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "TransactionsJsonV600(List(TransactionJsonV600(\n transaction_id = \"123\",\n this_account = ThisAccountJsonV600(\n bank_id = \"gh.29.uk\",\n account_id = \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n bank_routing = BankRoutingJsonV121(\"OBP\", \"gh.29.uk\"),\n account_routings = List(AccountRoutingJsonV121(\"OBP\", \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\")),\n holders = List(AccountHolderJSON(\"John Doe\", false))\n ),\n other_account = OtherAccountJsonV600(\n bank_id = \"other.bank.uk\",\n account_id = \"counterparty-123\",\n holder = AccountHolderJSON(\"Jane Smith\", false),\n bank_routing = BankRoutingJsonV121(\"OBP\", \"other.bank.uk\"),\n account_routings = List(AccountRoutingJsonV121(\"OBP\", \"counterparty-123\")),\n metadata = otherAccountMetadataJSON\n ),\n details = TransactionDetailsJSON(\n `type` = \"SEPA\",\n description = \"Payment for services\",\n posted = new java.util.Date(),\n completed = new java.util.Date(),\n new_balance = AmountOfMoneyJsonV121(\"EUR\", \"1000.00\"),\n value = AmountOfMoneyJsonV121(\"EUR\", \"100.00\")\n ),\n metadata = transactionMetadataJSON,\n transaction_attributes = Nil\n )))",
+ "error_response_bodies": "List(\n FilterSortDirectionError,\n FilterOffersetError,\n FilterLimitError,\n FilterDateFormatError,\n AuthenticatedUserIsRequired,\n BankAccountNotFound,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagTransaction, apiTagAccount)"
+ },
+ "getDynamicEntityDiagnostics": {
+ "partial_function_name_raw": "nameOf(getDynamicEntityDiagnostics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/diagnostics/dynamic-entities\"",
+ "summary": "\"Get Dynamic Entity Diagnostics\"",
+ "description": "s\"\"\"Get diagnostic information about Dynamic Entities to help troubleshoot Swagger generation issues.\n |\n |**Use Case:**\n |This endpoint is particularly useful when:\n |* The Swagger endpoint (`/obp/v6.0.0/resource-docs/OBPv6.0.0/swagger?content=dynamic`) fails with errors like \"expected boolean\"\n |* The OBP endpoint (`/obp/v6.0.0/resource-docs/OBPv6.0.0/obp?content=dynamic`) works fine\n |* You need to identify which dynamic entity has malformed field definitions\n |\n |**What It Checks:**\n |This endpoint analyzes all dynamic entities (both system and bank level) for:\n |* Boolean fields with invalid example values (e.g., actual JSON booleans or invalid strings instead of `\"true\"` or `\"false\"`)\n |* Malformed JSON in field definitions\n |* Fields that cannot be converted to their declared types\n |* Other validation issues that cause Swagger generation to fail\n |\n |**Response Format:**\n |The response contains:\n |* `issues` - List of issues found, each with:\n | * `entity_name` - Name of the problematic entity\n | * `bank_id` - Bank ID (or \"SYSTEM_LEVEL\" for system entities)\n | * `field_name` - Name of the problematic field\n | * `example_value` - The current (invalid) example value\n | * `error_message` - Description of what's wrong and how to fix it\n |* `total_issues` - Count of total issues found\n |* `scanned_entities` - List of all dynamic entities that were scanned (format: \"EntityName (BANK_ID)\" or \"EntityName (SYSTEM)\")\n |\n |**How to Fix Issues:**\n |1. Identify the problematic entity from the diagnostic output\n |2. Update the entity definition using PUT `/management/system-dynamic-entities/DYNAMIC_ENTITY_ID` or PUT `/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID`\n |3. For boolean fields, ensure the example value is either `\"true\"` or `\"false\"` (as strings)\n |4. Re-run this diagnostic to verify the fix\n |5. Check that the Swagger endpoint now works\n |\n |**Example Issue:**\n |```\n |{\n | \"entity_name\": \"Customer\",\n | \"bank_id\": \"gh.29.uk\",\n | \"field_name\": \"is_active\",\n | \"example_value\": \"malformed_value\",\n | \"error_message\": \"Boolean field has invalid example value. Expected 'true' or 'false', got: 'malformed_value'\"\n |}\n |```\n |\n |${userAuthenticationMessage(true)}\n |\n |**Required Role:** `CanGetDynamicEntityDiagnostics`\n |\n |If no issues are found, the response will contain an empty issues list with `total_issues: 0`, but `scanned_entities` will show which entities were checked.\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DynamicEntityDiagnosticsJsonV600(\n scanned_entities = List(\"MyEntity (gh.29.uk)\", \"AnotherEntity (SYSTEM)\"),\n issues = List(\n DynamicEntityIssueJsonV600(\n entity_name = \"MyEntity\",\n bank_id = \"gh.29.uk\",\n field_name = \"is_active\",\n example_value = \"malformed_value\",\n error_message = \"Boolean field has invalid example value. Expected 'true' or 'false', got: 'malformed_value'\"\n )\n ),\n total_issues = 1,\n orphaned_entities = List(\n OrphanedDynamicEntityJsonV600(\n entity_name = \"OldEntity\",\n bank_id = \"gh.29.uk\",\n record_count = 42\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicEntityDiagnostics))"
+ }
+ },
+ "cleanupOrphanedDynamicEntityRecords": {
+ "partial_function_name_raw": "nameOf(cleanupOrphanedDynamicEntityRecords)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/diagnostics/dynamic-entities/orphaned-records\"",
+ "summary": "\"Cleanup Orphaned Dynamic Entity Records\"",
+ "description": "s\"\"\"Delete orphaned dynamic entity data records.\n |\n |Orphaned records are rows in the DynamicData table whose entityName/bankId combination\n |has no matching Dynamic Entity definition. These can accumulate when entity definitions\n |are deleted but their data records are not cleaned up.\n |\n |This endpoint first identifies all orphaned records (using the same detection logic as\n |GET /management/diagnostics/dynamic-entities), then deletes them.\n |\n |**Response Format:**\n |* `deleted_orphaned_entities` - List of orphaned entity groups that were deleted, each with:\n | * `entity_name` - Name of the orphaned entity\n | * `bank_id` - Bank ID (or empty string for system-level)\n | * `record_count` - Number of records that were deleted for this entity group\n |* `total_records_deleted` - Total count of all deleted records\n |\n |Authentication is Required\n |\n |**Required Role:** `CanCleanupOrphanedDynamicEntityRecords`\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CleanupOrphanedDynamicEntityResponseJsonV600(\n deleted_orphaned_entities = List(\n OrphanedDynamicEntityJsonV600(\n entity_name = \"OldEntity\",\n bank_id = \"gh.29.uk\",\n record_count = 42\n )\n ),\n total_records_deleted = 42\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCleanupOrphanedDynamicEntityRecords))"
+ }
+ },
+ "getReferenceTypes": {
+ "partial_function_name_raw": "nameOf(getReferenceTypes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/dynamic-entities/reference-types\"",
+ "summary": "\"Get Reference Types for Dynamic Entities\"",
+ "description": "s\"\"\"Get a list of all available reference types that can be used in Dynamic Entity field definitions.\n |\n |Reference types allow Dynamic Entity fields to reference other entities (similar to foreign keys).\n |This endpoint returns both:\n |* **Static reference types** - Built-in reference types for core OBP entities (e.g., Customer, Account, Transaction)\n |* **Dynamic reference types** - Reference types for Dynamic Entities that have been created\n |\n |Each reference type includes:\n |* `type_name` - The full reference type string to use in entity definitions (e.g., \"reference:Customer\")\n |* `example_value` - An example value showing the correct format\n |* `description` - Description of what the reference type represents\n |\n |**Use Case:**\n |When creating a Dynamic Entity with a field that references another entity, you need to know:\n |1. What reference types are available\n |2. The correct format for the type name\n |3. The correct format for example values\n |\n |This endpoint provides all that information.\n |\n |**Example Usage:**\n |If you want to create a Dynamic Entity with a field that references a Customer, you would:\n |1. Call this endpoint to see that \"reference:Customer\" is available\n |2. Use it in your entity definition like:\n |```json\n |{\n | \"customer_id\": {\n | \"type\": \"reference:Customer\",\n | \"example\": \"a8770fca-3d1d-47af-b6d0-7a6c3f124388\"\n | }\n |}\n |```\n |\n |${userAuthenticationMessage(true)}\n |\n |**Required Role:** `CanGetDynamicEntityReferenceTypes`\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ReferenceTypesJsonV600(\n reference_types = List(\n ReferenceTypeJsonV600(\n type_name = \"reference:Customer\",\n example_value = \"a8770fca-3d1d-47af-b6d0-7a6c3f124388\",\n description = \"Reference to a Customer entity\"\n ),\n ReferenceTypeJsonV600(\n type_name = \"reference:Account:BANK_ID&ACCOUNT_ID\",\n example_value = \"BANK_ID=b9881ecb-4e2e-58bg-c7e1-8b7d4e235499&ACCOUNT_ID=c0992fdb-5f3f-69ch-d8f2-9c8e5f346600\",\n description = \"Composite reference to an Account by bank ID and account ID\"\n ),\n ReferenceTypeJsonV600(\n type_name = \"reference:MyDynamicEntity\",\n example_value = \"d1aa3gec-6g4g-70di-e9g3-0d9f6g457711\",\n description = \"Reference to MyDynamicEntity (dynamic entity)\"\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetDynamicEntityReferenceTypes))"
+ }
+ },
+ "getCurrentUser": {
+ "partial_function_name_raw": "nameOf(getCurrentUser)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current\"",
+ "summary": "\"Get User (Current)\"",
+ "description": "s\"\"\"Get the logged in user\n |\n |${userAuthenticationMessage(true)}\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userJsonV300",
+ "error_response_bodies": "List(AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagUser)"
+ },
+ "getUsers": {
+ "partial_function_name_raw": "nameOf(getUsers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Get all Users\"",
+ "description": "s\"\"\"Get all users, optionally filtered.\n |\n |All query parameters are optional and may be combined.\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required.\n |\n |${urlParametersDocument(false, false)}\n |* provider (if null ignore) - filter by identity provider, exact match\n |* username (if null ignore) - filter by username, exact match\n |* email (if null ignore) - filter by email, exact match (may return multiple users — duplicate emails are allowed in OBP by design)\n |* user_id (if null ignore) - filter by user_id, exact match\n |* locked_status (if null ignore) - \"active\" or \"locked\"\n |* is_deleted (default: false)\n |* role_name (if null ignore) - filter by entitlement/role name e.g. CanCreateAccount\n |* bank_id (if null ignore) - when used with role_name, filter entitlements by bank_id\n |* sort_by (if null ignore) - sort by field; allowed values: ${code.users.DoobieUserQueries.SortableColumns.keySet.toSeq.sorted.mkString(\", \")}\n |* sort_direction (if null defaults to DESC) - \"asc\" or \"desc\" (case-insensitive)\n |\n |When sort_by is omitted, results are ordered by insertion order ascending (stable pagination).\n |\n |Returns an empty list (not 404) when no users match.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "usersInfoJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n FilterSortByError,\n FilterSortByNotAllowedForEndpoint,\n FilterSortDirectionError,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getUserByUserId": {
+ "partial_function_name_raw": "nameOf(getUserByUserId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/user-id/USER_ID\"",
+ "summary": "\"Get User by USER_ID\"",
+ "description": "s\"\"\"Get user by USER_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetAnyUser entitlement is required,\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userInfoDetailJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAnyUser))"
+ }
+ },
+ "getMigrations": {
+ "partial_function_name_raw": "nameOf(getMigrations)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/migrations\"",
+ "summary": "\"Get Database Migrations\"",
+ "description": "s\"\"\"Get all database migration script logs.\n |\n |This endpoint returns information about all migration scripts that have been executed or attempted.\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetMigrations entitlement is required.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "migrationScriptLogsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMigrations))"
+ }
+ },
+ "getCacheNamespaces": {
+ "partial_function_name_raw": "nameOf(getCacheNamespaces)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/cache/namespaces\"",
+ "summary": "\"Get Cache Namespaces\"",
+ "description": "\"\"\"Returns information about all cache namespaces in the system.\n |\n |This endpoint provides visibility into:\n |* Cache namespace prefixes and their purposes\n |* Number of keys in each namespace\n |* TTL configurations\n |* Example keys for each namespace\n |\n |This is useful for:\n |* Monitoring cache usage\n |* Understanding cache structure\n |* Debugging cache-related issues\n |* Planning cache management operations\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "CacheNamespacesJsonV600(\n namespaces = List(\n CacheNamespaceJsonV600(\n prefix = \"call_counter_\",\n description = \"Rate limiting counters per consumer and time period\",\n ttl_seconds = \"varies\",\n category = \"Rate Limiting\",\n key_count = 42,\n example_key = \"rl_counter_consumer123_PER_MINUTE\"\n ),\n CacheNamespaceJsonV600(\n prefix = \"rl_active_\",\n description = \"Active rate limit configurations\",\n ttl_seconds = \"3600\",\n category = \"Rate Limiting\",\n key_count = 15,\n example_key = \"rl_active_consumer123_2024-12-27-14\"\n ),\n CacheNamespaceJsonV600(\n prefix = \"rd_localised_\",\n description = \"Localized resource documentation\",\n ttl_seconds = \"3600\",\n category = \"Resource Documentation\",\n key_count = 128,\n example_key = \"rd_localised_operationId:getBanks-locale:en\"\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCache, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCacheNamespaces))"
+ }
+ },
+ "createTransactionRequestCardano": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestCardano)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/CARDANO/transaction-requests\"",
+ "summary": "\"Create Transaction Request (CARDANO)\"",
+ "description": "s\"\"\"\n |\n |For sandbox mode, it will use the Cardano Preprod Network.\n |The accountId can be the wallet_id for now, as it uses cardano-wallet in the backend.\n |\n |${transactionRequestGeneralText}\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyCardanoJsonV600",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestEthereumeSendTransaction": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestEthereumeSendTransaction)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_TRANSACTION/transaction-requests\"",
+ "summary": "\"Create Transaction Request (ETH_SEND_TRANSACTION)\"",
+ "description": "s\"\"\"\n |\n |Send ETH via Ethereum JSON-RPC.\n |AccountId should hold the 0x address for now.\n |\n |${transactionRequestGeneralText}\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyEthereumJsonV600",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createTransactionRequestEthSendRawTransaction": {
+ "partial_function_name_raw": "nameOf(createTransactionRequestEthSendRawTransaction)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_RAW_TRANSACTION/transaction-requests\"",
+ "summary": "\"CREATE TRANSACTION REQUEST (ETH_SEND_RAW_TRANSACTION )\"",
+ "description": "s\"\"\"\n |\n |Send ETH via Ethereum JSON-RPC.\n |AccountId should hold the 0x address for now.\n |\n |${transactionRequestGeneralText}\n |\n \"\"\".stripMargin",
+ "example_request_body": "transactionRequestBodyEthSendRawTransactionJsonV600",
+ "success_response_body": "transactionRequestWithChargeJSON400",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n InsufficientAuthorisationToCreateTransactionRequest,\n InvalidTransactionRequestType,\n InvalidJsonFormat,\n NotPositiveAmount,\n InvalidTransactionRequestCurrency,\n TransactionDisabled,\n UnknownError\n )",
+ "tags": "List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)"
+ },
+ "createBank": {
+ "partial_function_name_raw": "\"createBank\"",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks\"",
+ "summary": "\"Create Bank\"",
+ "description": "s\"\"\"Create a new bank (Authenticated access).\n |\n |The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.\n |Thus the User can manage the bank they create and assign Roles to other Users.\n |\n Only SANDBOX mode (i.e. when connector=mapped in properties file)\n |The settlement accounts are automatically created by the system when the bank is created.\n |Name and account id are created in accordance to the next rules:\n | - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)\n | - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)\n |\n |\"\"\"",
+ "example_request_body": "postBankJson600",
+ "success_response_body": "bankJson600",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n $AuthenticatedUserIsRequired,\n InsufficientAuthorisationToCreateBank,\n UnknownError\n )",
+ "tags": "List(apiTagBank)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBank))"
+ }
+ },
+ "getProviders": {
+ "partial_function_name_raw": "nameOf(getProviders)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/providers\"",
+ "summary": "\"Get Providers\"",
+ "description": "s\"\"\"Get the list of authentication providers that have been used to create users on this OBP instance.\n |\n |This endpoint returns a distinct list of provider values from the resource_user table.\n |\n |Providers may include:\n |* Local OBP provider (e.g., \"http://127.0.0.1:8080\")\n |* OAuth 2.0 / OpenID Connect providers (e.g., \"google.com\", \"microsoft.com\")\n |* Custom authentication providers\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.createProvidersJson(List(\"http://127.0.0.1:8080\", \"OBP\", \"google.com\"))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getConnectorMethodNames": {
+ "partial_function_name_raw": "nameOf(getConnectorMethodNames)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/connector-method-names\"",
+ "summary": "\"Get Connector Method Names\"",
+ "description": "s\"\"\"Get the list of all available connector method names.\n |\n |These are the method names that can be used in Method Routing configuration.\n |\n |## Data Source\n |\n |The data comes from **scanning the actual Scala connector code at runtime** using reflection, NOT from a database or configuration file.\n |\n |The endpoint:\n |1. Reads the connector name from props (e.g., `connector=mapped`)\n |2. Gets the connector instance (e.g., LocalMappedConnector, KafkaConnector, StarConnector)\n |3. Uses Scala reflection to scan all public methods that override the base Connector trait\n |4. Filters for valid connector methods (public, has parameters, overrides base trait)\n |5. Returns the method names as a sorted list\n |\n |## Which Connector?\n |\n |Depends on your `connector` property:\n |* `connector=mapped` → Returns methods from LocalMappedConnector\n |* `connector=kafka_vSept2018` → Returns methods from KafkaConnector\n |* `connector=star` → Returns methods from StarConnector\n |* `connector=rest_vMar2019` → Returns methods from RestConnector\n |\n |## When Does It Change?\n |\n |The list only changes when:\n |* Code is deployed with new/modified connector methods\n |* The `connector` property is changed to point to a different connector\n |\n |## Performance\n |\n |This endpoint uses caching (default: 1 hour) because Scala reflection is expensive.\n |Configure via: `getConnectorMethodNames.cache.ttl.seconds=3600`\n |\n |## Use Case\n |\n |Use this endpoint to discover which connector methods are available when configuring Method Routing.\n |These method names are different from API endpoint operation IDs (which you get from /resource-docs).\n |\n |${userAuthenticationMessage(true)}\n |\n |CanGetSystemConnectorMethodNames entitlement is required.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ConnectorMethodNamesJsonV600(List(\"getBank\", \"getBanks\", \"getUser\", \"getAccount\", \"makePayment\", \"getTransactions\"))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagConnectorMethod, apiTagSystem, apiTagMethodRouting, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemConnectorMethodNames))"
+ }
+ },
+ "getConnectors": {
+ "partial_function_name_raw": "nameOf(getConnectors)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/system/connectors\"",
+ "summary": "\"Get Connectors\"",
+ "description": "s\"\"\"Get the list of connectors and their availability for method routing.\n |\n |Returns a sorted list of all connectors with their availability status for use in Method Routing.\n |\n |## Response Fields\n |\n |* **connector_name** - The name of the connector\n |* **is_available_in_method_routing** - Whether this connector can be used in Method Routing configuration.\n | This depends on the `connector` and `starConnector_supported_types` props settings.\n |\n |## Available Connectors\n |\n |The OBP-API supports multiple connectors for accessing banking data:\n |\n |* **mapped** - Local database connector using Lift Mapper ORM\n |* **akka_vDec2018** - Akka-based connector for remote banking systems\n |* **rest_vMar2019** - REST connector for external APIs\n |* **stored_procedure_vDec2019** - Stored procedure connector for database-native operations\n |* **rabbitmq_vOct2024** - RabbitMQ message queue connector\n |* **cardano_vJun2025** - Cardano blockchain connector\n |* **ethereum_vSept2025** - Ethereum blockchain connector\n |* **star** - Star connector (special routing connector)\n |* **proxy** - Proxy connector (for testing)\n |* **internal** - Internal dynamic connector\n |\n |## Use Case\n |\n |Use this endpoint to discover which connectors are available when configuring Method Routing.\n |A connector is available for method routing if it matches the `connector` prop setting,\n |or if `connector=star` and the connector is listed in `starConnector_supported_types`.\n |\n |Authentication is Optional.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ConnectorsJsonV600(List(\n ConnectorInfoJsonV600(\"mapped\", true),\n ConnectorInfoJsonV600(\"akka_vDec2018\", false),\n ConnectorInfoJsonV600(\"rest_vMar2019\", true),\n ConnectorInfoJsonV600(\"stored_procedure_vDec2019\", false)\n ))",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagConnector, apiTagSystem, apiTagApi)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getTopAPIs": {
+ "partial_function_name_raw": "nameOf(getTopAPIs)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics/top-apis\"",
+ "summary": "\"Get Top APIs\"",
+ "description": "s\"\"\"Get metrics about the most popular APIs. e.g.: total count, response time (in ms), etc.\n |\n |This v6.0.0 version includes the **operation_id** field which uniquely identifies each API endpoint\n |across different API standards (OBP, Berlin Group, UK Open Banking, etc.).\n |\n |Should be able to filter on the following fields:\n |\n |eg: /management/metrics/top-apis?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |1 from_date (defaults to one year ago): eg:from_date=$epochTimeString\n |\n |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two values: true (return where user_id is null) or false (return where user_id is not null)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore)\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 duration (if null ignore) non digit chars will be silently omitted\n |\n |13 exclude_app_names (if null ignore). eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |14 exclude_url_patterns (if null ignore). You can design your own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |15 exclude_implemented_by_partial_functions (if null ignore). eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |${userAuthenticationMessage(true)}\n |\n |CanReadMetrics entitlement is required.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "TopApisJsonV600(List(\n TopApiJsonV600(1000, \"getBanks\", \"v4.0.0\", \"OBPv4.0.0-getBanks\"),\n TopApiJsonV600(500, \"getBank\", \"v4.0.0\", \"OBPv4.0.0-getBank\"),\n TopApiJsonV600(250, \"getAccountList\", \"v1.3\", \"BGv1.3-getAccountList\")\n ))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidFilterParameterFormat,\n GetTopApisError,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "getScannedApiVersions": {
+ "partial_function_name_raw": "nameOf(getScannedApiVersions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api/versions\"",
+ "summary": "\"Get Scanned API Versions\"",
+ "description": "s\"\"\"Get all scanned API versions available in this codebase.\n |\n |This endpoint returns all API versions that have been discovered/scanned, along with their active status.\n |\n |**Response Fields:**\n |\n |* `url_prefix`: The URL prefix for the version (e.g., \"obp\", \"berlin-group\", \"open-banking\")\n |* `api_standard`: The API standard name (e.g., \"OBP\", \"BG\", \"UK\", \"STET\")\n |* `api_short_version`: The version number (e.g., \"v4.0.0\", \"v1.3\")\n |* `fully_qualified_version`: The fully qualified version combining standard and version (e.g., \"OBPv4.0.0\", \"BGv1.3\")\n |* `is_active`: Boolean indicating if the version is currently enabled and accessible\n |\n |**Active Status:**\n |\n |* `is_active=true`: Version is enabled and can be accessed via its URL prefix\n |* `is_active=false`: Version is scanned but disabled (via `api_disabled_versions` props)\n |\n |**Use Cases:**\n |\n |* Discover what API versions are available in the codebase\n |* Check which versions are currently enabled\n |* Verify that disabled versions configuration is working correctly\n |* API documentation and discovery\n |\n |**Note:** This differs from v4.0.0's `/api/versions` endpoint which shows all scanned versions without is_active status.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"scanned_api_versions\",\n List(\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v1_2_1.toString, fully_qualified_version = ApiVersion.v1_2_1.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v1_3_0.toString, fully_qualified_version = ApiVersion.v1_3_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v1_4_0.toString, fully_qualified_version = ApiVersion.v1_4_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v2_0_0.toString, fully_qualified_version = ApiVersion.v2_0_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v2_1_0.toString, fully_qualified_version = ApiVersion.v2_1_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v2_2_0.toString, fully_qualified_version = ApiVersion.v2_2_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v3_0_0.toString, fully_qualified_version = ApiVersion.v3_0_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v3_1_0.toString, fully_qualified_version = ApiVersion.v3_1_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v4_0_0.toString, fully_qualified_version = ApiVersion.v4_0_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v5_0_0.toString, fully_qualified_version = ApiVersion.v5_0_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v5_1_0.toString, fully_qualified_version = ApiVersion.v5_1_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"obp\", api_standard = \"OBP\", api_short_version = ApiVersion.v6_0_0.toString, fully_qualified_version = ApiVersion.v6_0_0.fullyQualifiedVersion, is_active = true),\n ScannedApiVersionJsonV600(url_prefix = \"berlin-group\", api_standard = \"BG\", api_short_version = \"v1.3\", fully_qualified_version = \"BGv1.3\", is_active = false)\n )\n )",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagDocumentation, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(Nil)"
+ }
+ },
+ "createCustomer": {
+ "partial_function_name_raw": "nameOf(createCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Create Customer\"",
+ "description": "s\"\"\"\n |The Customer resource stores the customer number, legal name, email, phone number, date of birth, relationship status,\n |education attained, a url for a profile image, KYC status, credit rating, credit limit, and other customer information.\n |\n |**Required Fields:**\n |- legal_name: The customer's full legal name\n |- mobile_phone_number: The customer's mobile phone number\n |\n |**Optional Fields:**\n |- customer_number: If not provided, a random number will be generated\n |- email: Customer's email address\n |- face_image: Customer's face image (url and date)\n |- date_of_birth: Customer's date of birth in YYYY-MM-DD format\n |- relationship_status: Customer's relationship status\n |- dependants: Number of dependants (must match the length of dob_of_dependants array)\n |- dob_of_dependants: Array of dependant birth dates in YYYY-MM-DD format\n |- credit_rating: Customer's credit rating (rating and source)\n |- credit_limit: Customer's credit limit (currency and amount)\n |- highest_education_attained: Customer's highest education level\n |- employment_status: Customer's employment status\n |- kyc_status: Know Your Customer verification status (true/false). Default: false\n |- last_ok_date: Last verification date\n |- title: Customer's title (e.g., Mr., Mrs., Dr.)\n |- branch_id: Associated branch identifier\n |- name_suffix: Customer's name suffix (e.g., Jr., Sr.)\n |- customer_type: Type of customer - INDIVIDUAL (default), CORPORATE, or SUBSIDIARY\n |- parent_customer_id: For SUBSIDIARY customers, the customer_id of the parent CORPORATE customer\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants must be provided in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |The dates are strictly validated and must be valid calendar dates.\n |Dates are stored with time set to midnight (00:00:00) UTC for consistency.\n |\n |**Validations:**\n |- customer_number cannot contain `::::` characters\n |- customer_number must be unique for the bank\n |- The number of dependants must equal the length of the dob_of_dependants array\n |- date_of_birth must be in valid YYYY-MM-DD format if provided\n |- Each date in dob_of_dependants must be in valid YYYY-MM-DD format\n |\n |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "postCustomerJsonV600",
+ "success_response_body": "customerJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n InvalidJsonContent,\n InvalidDateFormat,\n InvalidCustomerType,\n ParentCustomerNotFound,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagPerson)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer,canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getCustomerChildren": {
+ "partial_function_name_raw": "nameOf(getCustomerChildren)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/children\"",
+ "summary": "\"Get Customer Children\"",
+ "description": "s\"\"\"Get the child (subsidiary) customers of a parent customer.\n |\n |Returns a list of customers whose parent_customer_id matches the specified CUSTOMER_ID.\n |This is useful for corporate banking where a corporate customer may have subsidiary customers.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomersAtAllBanks": {
+ "partial_function_name_raw": "nameOf(getCustomersAtAllBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/customers\"",
+ "summary": "\"Get Customers at All Banks\"",
+ "description": "s\"\"\"Get Customers at All Banks.\n |\n |Returns a list of all customers across all banks.\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |\n |**Query Parameters:**\n |- limit: Maximum number of customers to return (optional)\n |- offset: Number of customers to skip for pagination (optional)\n |- sort_direction: Sort direction - ASC or DESC (optional)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtAllBanks))"
+ }
+ },
+ "getCustomersByLegalName": {
+ "partial_function_name_raw": "nameOf(getCustomersByLegalName)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/legal-name\"",
+ "summary": "\"Get Customers by Legal Name\"",
+ "description": "s\"\"\"Gets the Customers specified by Legal Name.\n |\n |Returns a list of customers that match the provided legal name.\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PostCustomerLegalNameJsonV510(legal_name = \"John Smith\")",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomersAtOneBank": {
+ "partial_function_name_raw": "nameOf(getCustomersAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers\"",
+ "summary": "\"Get Customers at Bank\"",
+ "description": "s\"\"\"Get Customers at Bank.\n |\n |Returns a list of all customers at the specified bank.\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |\n |**Query Parameters:**\n |- limit: Maximum number of customers to return (optional)\n |- offset: Number of customers to skip for pagination (optional)\n |- sort_direction: Sort direction - ASC or DESC (optional)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomerByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCustomerByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID\"",
+ "summary": "\"Get Customer by CUSTOMER_ID\"",
+ "description": "s\"\"\"Gets the Customer specified by CUSTOMER_ID.\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerWithAttributesJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCustomerByCustomerNumber": {
+ "partial_function_name_raw": "nameOf(getCustomerByCustomerNumber)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customers/customer-number\"",
+ "summary": "\"Get Customer by CUSTOMER_NUMBER\"",
+ "description": "s\"\"\"Gets the Customer specified by CUSTOMER_NUMBER.\n |\n |**Date Format:**\n |In v6.0.0, date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD** (e.g., \"1990-05-15\", \"2010-03-20\").\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "postCustomerNumberJsonV310",
+ "success_response_body": "customerWithAttributesJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserCustomerLinksNotFoundForUser,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "createRetailCustomer": {
+ "partial_function_name_raw": "nameOf(createRetailCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/retail-customers\"",
+ "summary": "\"Create Retail Customer\"",
+ "description": "s\"\"\"Create a retail (individual) customer.\n |\n |This endpoint is specifically for creating individual/retail customers.\n |The customer_type will be automatically set to INDIVIDUAL.\n |\n |**Required Fields:**\n |- legal_name: The customer's full legal name\n |- mobile_phone_number: The customer's mobile phone number\n |\n |**Optional Fields:**\n |- customer_number: If not provided, a random number will be generated\n |- email, face_image, date_of_birth, relationship_status, dependants, dob_of_dependants\n |- credit_rating, credit_limit, highest_education_attained, employment_status\n |- kyc_status, last_ok_date, title, branch_id, name_suffix\n |\n |**Date Format:**\n |date_of_birth and dob_of_dependants must be in ISO 8601 date format: **YYYY-MM-DD**\n |\n |**Validations:**\n |- customer_number cannot contain `::::` characters\n |- customer_number must be unique for the bank\n |- The number of dependants must equal the length of the dob_of_dependants array\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "postRetailCustomerJsonV600",
+ "success_response_body": "customerJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n InvalidJsonContent,\n InvalidDateFormat,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagRetailCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getRetailCustomersAtOneBank": {
+ "partial_function_name_raw": "nameOf(getRetailCustomersAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/retail-customers\"",
+ "summary": "\"Get Retail Customers at Bank\"",
+ "description": "s\"\"\"Get Retail (Individual) Customers at Bank.\n |\n |Returns a list of customers with customer_type INDIVIDUAL at the specified bank.\n |\n |**Date Format:**\n |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**\n |\n |**Query Parameters:**\n |- limit: Maximum number of customers to return (optional)\n |- offset: Number of customers to skip for pagination (optional)\n |- sort_direction: Sort direction - ASC or DESC (optional)\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagRetailCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getRetailCustomerByCustomerId": {
+ "partial_function_name_raw": "nameOf(getRetailCustomerByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/retail-customers/CUSTOMER_ID\"",
+ "summary": "\"Get Retail Customer by CUSTOMER_ID\"",
+ "description": "s\"\"\"Gets the Retail Customer specified by CUSTOMER_ID.\n |\n |Returns 404 if the customer exists but is not of type INDIVIDUAL.\n |Use the generic /customers/CUSTOMER_ID endpoint for any customer type.\n |\n |**Date Format:**\n |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerWithAttributesJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n CustomerTypeMismatch,\n UnknownError\n )",
+ "tags": "List(apiTagRetailCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "createCorporateCustomer": {
+ "partial_function_name_raw": "nameOf(createCorporateCustomer)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/corporate-customers\"",
+ "summary": "\"Create Corporate Customer\"",
+ "description": "s\"\"\"Create a corporate customer.\n |\n |This endpoint is specifically for creating corporate customers.\n |Individual-oriented fields (relationship_status, dependants, highest_education_attained, employment_status, name_suffix, date_of_birth, face_image, title) are not available on this endpoint.\n |\n |**Required Fields:**\n |- legal_name: The corporate entity's legal name\n |- mobile_phone_number: The corporate entity's phone number\n |\n |**Optional Fields:**\n |- customer_number: If not provided, a random number will be generated\n |- email, credit_rating, credit_limit, kyc_status, last_ok_date, branch_id\n |- customer_type: CORPORATE (default) or SUBSIDIARY\n |- parent_customer_id: For SUBSIDIARY customers, the customer_id of the parent customer\n |\n |**Validations:**\n |- customer_number cannot contain `::::` characters\n |- customer_number must be unique for the bank\n |- customer_type must be CORPORATE or SUBSIDIARY\n |- parent_customer_id must reference an existing customer if provided\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "postCorporateCustomerJsonV600",
+ "success_response_body": "customerJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n InvalidCustomerType,\n ParentCustomerNotFound,\n CustomerNumberAlreadyExists,\n UserNotFoundById,\n CustomerAlreadyExistsForUser,\n CreateConsumerError,\n UnknownError\n )",
+ "tags": "List(apiTagCorporateCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomer, canCreateCustomerAtAnyBank))"
+ }
+ },
+ "getCorporateCustomersAtOneBank": {
+ "partial_function_name_raw": "nameOf(getCorporateCustomersAtOneBank)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/corporate-customers\"",
+ "summary": "\"Get Corporate Customers at Bank\"",
+ "description": "s\"\"\"Get Corporate Customers at Bank.\n |\n |Returns a list of customers with customer_type CORPORATE or SUBSIDIARY at the specified bank.\n |\n |**Date Format:**\n |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**\n |\n |**Query Parameters:**\n |- limit: Maximum number of customers to return (optional)\n |- offset: Number of customers to skip for pagination (optional)\n |- sort_direction: Sort direction - ASC or DESC (optional)\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagCorporateCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCorporateCustomerByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCorporateCustomerByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/corporate-customers/CUSTOMER_ID\"",
+ "summary": "\"Get Corporate Customer by CUSTOMER_ID\"",
+ "description": "s\"\"\"Gets the Corporate Customer specified by CUSTOMER_ID.\n |\n |Returns 404 if the customer exists but is not of type CORPORATE or SUBSIDIARY.\n |Use the generic /customers/CUSTOMER_ID endpoint for any customer type.\n |\n |**Date Format:**\n |date_of_birth and dob_of_dependants are returned in ISO 8601 date format: **YYYY-MM-DD**\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerWithAttributesJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n CustomerTypeMismatch,\n UnknownError\n )",
+ "tags": "List(apiTagCorporateCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getCorporateCustomerSubsidiaries": {
+ "partial_function_name_raw": "nameOf(getCorporateCustomerSubsidiaries)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/corporate-customers/CUSTOMER_ID/subsidiaries\"",
+ "summary": "\"Get Corporate Customer Subsidiaries\"",
+ "description": "s\"\"\"Get the subsidiary customers of a corporate customer.\n |\n |Returns a list of customers whose parent_customer_id matches the specified CUSTOMER_ID.\n |The specified customer must be of type CORPORATE or SUBSIDIARY.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerJSONsV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n CustomerTypeMismatch,\n UnknownError\n )",
+ "tags": "List(apiTagCorporateCustomer, apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomersAtOneBank))"
+ }
+ },
+ "getMetrics": {
+ "partial_function_name_raw": "nameOf(getMetrics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/metrics\"",
+ "summary": "\"Get Metrics\"",
+ "description": "s\"\"\"Get API metrics rows. These are records of each REST API call.\n |\n |require CanReadMetrics role\n |\n |**NOTE: Automatic from_date Default**\n |\n |If you do not provide a `from_date` parameter, this endpoint will automatically set it to:\n |**now - ${(APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt - 1) / 60} minutes ago**\n |\n |This prevents accidentally querying all metrics since Unix Epoch and ensures reasonable response times.\n |For historical/reporting queries, always explicitly specify your desired `from_date`.\n |\n |**IMPORTANT: Smart Caching & Performance**\n |\n |This endpoint uses intelligent two-tier caching to optimize performance:\n |\n |**Stable Data Cache (Long TTL):**\n |- Metrics older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} minutes) are considered immutable/stable\n |- These are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours)\n |- Used when your query's from_date is older than the stable boundary\n |\n |**Recent Data Cache (Short TTL):**\n |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds\n |- Used when your query includes recent data or has no from_date\n |\n |**STRONGLY RECOMMENDED: Always specify from_date in your queries!**\n |\n |**Why from_date matters:**\n |- Queries WITH from_date older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} mins → cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours (fast!)\n |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds (slower)\n |\n |**Examples:**\n |- `from_date=2025-01-01T00:00:00.000Z` → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours cache (historical data)\n |- `from_date=$DateWithMsExampleString` (recent date) → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds cache (recent data)\n |- No from_date → **Automatically set to ${(APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt - 1) / 60} minutes ago** → Uses ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds cache (recent data)\n |\n |For best performance on historical/reporting queries, always include a from_date parameter!\n |\n |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics\n |\n |You can filter by the following fields by applying url parameters\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date e.g.:from_date=$DateWithMsExampleString\n | **DEFAULT**: If not provided, automatically set to now - ${(APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt - 1) / 60} minutes (keeps queries in recent data zone)\n | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!\n |\n |2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}\n |\n |3 limit (for pagination: defaults to 50) eg:limit=200\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |5 sort_by (defaults to date field) eg: sort_by=date\n | possible values:\n | \"url\",\n | \"date\",\n | \"username\" (or \"user_name\" for backward compatibility),\n | \"app_name\",\n | \"developer_email\",\n | \"implemented_by_partial_function\",\n | \"implemented_in_version\",\n | \"consumer_id\",\n | \"verb\"\n |\n |6 direction (defaults to date desc) eg: direction=desc\n |\n |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&username=susan.uk.29@example.com&consumer_id=78\n |\n |Other filters:\n |\n |7 consumer_id (if null ignore)\n |\n |8 user_id (if null ignore)\n |\n |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |10 url (if null ignore), note: can not contain '&'.\n |\n |11 app_name (if null ignore)\n |\n |12 implemented_by_partial_function (if null ignore),\n |\n |13 implemented_in_version (if null ignore)\n |\n |14 verb (if null ignore)\n |\n |15 correlation_id (if null ignore)\n |\n |16 duration (if null ignore) - Returns calls where duration > specified value (in milliseconds). Use this to find slow API calls. eg: duration=5000 returns calls taking more than 5 seconds\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "metricsJsonV600",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "getAggregateMetrics": {
+ "partial_function_name_raw": "nameOf(getAggregateMetrics)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/aggregate-metrics\"",
+ "summary": "\"Get Aggregate Metrics\"",
+ "description": "s\"\"\"Returns aggregate metrics on api usage eg. total count, response time (in ms), etc.\n |\n |require CanReadAggregateMetrics role\n |\n |**NOTE: Automatic from_date Default**\n |\n |If you do not provide a `from_date` parameter, this endpoint will automatically set it to:\n |**now - ${(APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt - 1) / 60} minutes ago**\n |\n |This prevents accidentally querying all metrics since Unix Epoch and ensures reasonable response times.\n |For historical/reporting queries, always explicitly specify your desired `from_date`.\n |\n |**IMPORTANT: Smart Caching & Performance**\n |\n |This endpoint uses intelligent two-tier caching to optimize performance:\n |\n |**Stable Data Cache (Long TTL):**\n |- Metrics older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} minutes) are considered immutable/stable\n |- These are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\")} seconds (${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours)\n |- Used when your query's from_date is older than the stable boundary\n |\n |**Recent Data Cache (Short TTL):**\n |- Recent metrics (within the stable boundary) are cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds\n |- Used when your query includes recent data or has no from_date\n |\n |**Why from_date matters:**\n |- Queries WITH from_date older than ${APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt / 60} mins → cached for ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getStableMetrics\", \"86400\").toInt / 3600} hours (fast!)\n |- Queries WITHOUT from_date → cached for only ${APIUtil.getPropsValue(\"MappedMetrics.cache.ttl.seconds.getAllMetrics\", \"7\")} seconds (slower)\n |\n |Should be able to filter on the following fields\n |\n |eg: /management/aggregate-metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&consumer_id=5\n |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount\n |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions\n |&verb=GET&anon=false&app_name=MapperPostman\n |&include_app_names=API-EXPLORER,API-Manager,SOFI,null&http_status_code=200\n |\n |**IMPORTANT: v6.0.0+ Breaking Change**\n |\n |This version does NOT support the old `exclude_*` parameters:\n |- `exclude_app_names` - NOT supported (returns error)\n |- `exclude_url_patterns` - NOT supported (returns error)\n |- `exclude_implemented_by_partial_functions` - NOT supported (returns error)\n |\n |Use `include_*` parameters instead (all optional):\n |- `include_app_names` - Optional - include only these apps\n |- `include_url_patterns` - Optional - include only URLs matching these patterns\n |- `include_implemented_by_partial_functions` - Optional - include only these functions\n |\n |1 from_date e.g.:from_date=$DateWithMsExampleString\n | **DEFAULT**: If not provided, automatically set to now - ${(APIUtil.getPropsValue(\"MappedMetrics.stable.boundary.seconds\", \"600\").toInt - 1) / 60} minutes (keeps queries in recent data zone)\n | **IMPORTANT**: Including from_date enables long-term caching for historical data queries!\n |\n |2 to_date (defaults to the current date) eg:to_date=$DateWithMsExampleString\n |\n |3 consumer_id (if null ignore)\n |\n |4 user_id (if null ignore)\n |\n |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.)\n |\n |6 url (if null ignore), note: can not contain '&'.\n |\n |7 app_name (if null ignore)\n |\n |8 implemented_by_partial_function (if null ignore)\n |\n |9 implemented_in_version (if null ignore)\n |\n |10 verb (if null ignore)\n |\n |11 correlation_id (if null ignore)\n |\n |12 include_app_names (if null ignore).eg: &include_app_names=API-EXPLORER,API-Manager,SOFI,null\n |\n |13 include_url_patterns (if null ignore).you can design you own SQL LIKE pattern. eg: &include_url_patterns=%management/metrics%,%management/aggregate-metrics%\n |\n |14 include_implemented_by_partial_functions (if null ignore).eg: &include_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics\n |\n |15 http_status_code (if null ignore) - Filter by HTTP status code. eg: http_status_code=200 returns only successful calls, http_status_code=500 returns server errors\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "aggregateMetricsJSONV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagAggregateMetrics)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadAggregateMetrics))"
+ }
+ },
+ "directLoginEndpoint": {
+ "partial_function_name_raw": "nameOf(directLoginEndpoint)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/logins/direct\"",
+ "summary": "\"Direct Login\"",
+ "description": "s\"\"\"DirectLogin is a simple authentication flow. You POST your credentials (username, password, and consumer key)\n |to the DirectLogin endpoint and receive a token in return.\n |\n |This is an alias to the DirectLogin endpoint that includes the standard API versioning prefix.\n |\n |This endpoint requires the following header:\n |\n | DirectLogin: username=YOUR_USERNAME, password=YOUR_PASSWORD, consumer_key=YOUR_CONSUMER_KEY\n |\n |Note: You can also use the Authorization header (Authorization: DirectLogin username=...) but the DirectLogin header is preferred.\n |\n |The token returned can then be used in subsequent API calls using the header:\n |\n | DirectLogin: token=YOUR_TOKEN\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.createTokenJSON(\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJpYXQiOjE0NTU4OTQyNzYsImV4cCI6MTQ1NTg5Nzg3NiwiYXVkIjoib2JwLWFwaSIsInN1YiI6IjA2Zjc0YjUwLTA5OGYtNDYwNi1hOGNjLTBjNDc5MjAyNmI5ZCIsImNvbnN1bWVyX2tleSI6IjYwNGY3ZTAyNGQ5MWU2MzMwNGMzOGM0YzRmZjc0MjMwZGU5NDk4NTEwNjgxZWNjM2Q5MzViNWQ5MGEwOTI3ODciLCJyb2xlIjoiY2FuX2FjY2Vzc19hcGkifQ.f8xHvXP5fDxo5-LlfTj1OQS9oqHNZfFd7N-WkV2o4Cc\")",
+ "error_response_bodies": "List(\n InvalidDirectLoginParameters,\n InvalidLoginCredentials,\n InvalidConsumerCredentials,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "validateUserEmail": {
+ "partial_function_name_raw": "nameOf(validateUserEmail)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/email-validation\"",
+ "summary": "\"Validate User Email\"",
+ "description": "s\"\"\"Validate a user's email address using the JWT token sent via email.\n |\n |This is a self-service endpoint for users to confirm their email address as part of the sign-up process.\n |\n |When a user registers and email validation is enabled (authUser.skipEmailValidation=false),\n |they receive an email containing a validation link with a signed JWT token.\n |The user (or a client application) then calls this endpoint with that token to complete validation.\n |\n |This endpoint:\n |- Verifies the JWT signature and checks expiry\n |- Extracts the unique ID from the JWT subject\n |- Sets the user's validated status to true\n |- Resets the unique ID token (invalidating the link)\n |- Grants default entitlements to the user\n |\n |**Important: This is a single-use token.** Once the email is validated, the token is invalidated.\n |Any subsequent attempts to use the same token will return a 404 error (UserNotFoundByToken or UserAlreadyValidated).\n |\n |The token is a signed JWT with a configurable expiry (default: 1440 minutes / 24 hours).\n |The server-side expiry can be configured with the `email_validation_token_expiry_minutes` property.\n |\n |For administrative validation (without an email token), see the Validate a User endpoint (PUT /management/users/USER_ID).\n |\n |${userAuthenticationMessage(false)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "JSONFactory600.ValidateUserEmailJsonV600(\n token = \"eyJhbGciOiJIUzI1NiJ9...\"\n )",
+ "success_response_body": "JSONFactory600.ValidateUserEmailResponseJsonV600(\n user_id = \"5995d6a2-01b3-423c-a173-5481df49bdaf\",\n email = \"user@example.com\",\n username = \"username\",\n provider = \"https://localhost:8080\",\n validated = true,\n message = \"Email validated successfully\"\n )",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UserNotFoundByToken,\n UserAlreadyValidated,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "createGroup": {
+ "partial_function_name_raw": "nameOf(createGroup)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/groups\"",
+ "summary": "\"Create Group\"",
+ "description": "s\"\"\"Create a new group of roles.\n |\n |Groups can be either:\n |- System-level (bank_id = null) - requires CanCreateGroupAtAllBanks role\n |- Bank-level (bank_id provided) - requires CanCreateGroupAtOneBank role\n |\n |A group contains a list of role names that can be assigned together.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostGroupJsonV600(\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n group_description = \"Standard teller roles for branch operations\",\n list_of_roles = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\"),\n is_enabled = true\n )",
+ "success_response_body": "GroupJsonV600(\n group_id = \"group-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n group_description = \"Standard teller roles for branch operations\",\n list_of_roles = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\"),\n is_enabled = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagGroup)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateGroupAtAllBanks, canCreateGroupAtOneBank))"
+ }
+ },
+ "getGroup": {
+ "partial_function_name_raw": "nameOf(getGroup)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/groups/GROUP_ID\"",
+ "summary": "\"Get Group\"",
+ "description": "s\"\"\"Get a group by its ID.\n |\n |Requires either:\n |- CanGetGroupsAtAllBanks (for any group)\n |- CanGetGroupsAtOneBank (for groups at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "GroupJsonV600(\n group_id = \"group-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n group_description = \"Standard teller roles for branch operations\",\n list_of_roles = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\"),\n is_enabled = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetGroupsAtAllBanks, canGetGroupsAtOneBank))"
+ }
+ },
+ "getGroups": {
+ "partial_function_name_raw": "nameOf(getGroups)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/groups\"",
+ "summary": "\"Get Groups\"",
+ "description": "s\"\"\"Get all groups. Optionally filter by bank_id.\n |\n |Query parameters:\n |- bank_id (optional): Filter groups by bank. Use \"null\" or omit for system-level groups.\n |\n |Requires either:\n |- CanGetGroupsAtAllBanks (for any/all groups)\n |- CanGetGroupsAtOneBank (for groups at specific bank with bank_id parameter)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "GroupsJsonV600(\n groups = List(\n GroupJsonV600(\n group_id = \"group-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n group_description = \"Standard teller roles\",\n list_of_roles = List(\"CanGetCustomer\", \"CanGetAccount\"),\n is_enabled = true\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetGroupsAtAllBanks, canGetGroupsAtOneBank))"
+ }
+ },
+ "updateGroup": {
+ "partial_function_name_raw": "nameOf(updateGroup)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/groups/GROUP_ID\"",
+ "summary": "\"Update Group\"",
+ "description": "s\"\"\"Update a group. All fields are optional.\n |\n |Requires either:\n |- CanUpdateGroupAtAllBanks (for any group)\n |- CanUpdateGroupAtOneBank (for groups at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutGroupJsonV600(\n group_name = Some(\"Updated Teller Group\"),\n group_description = Some(\"Updated description\"),\n list_of_roles = Some(List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\", \"CanGetTransaction\")),\n is_enabled = Some(true)\n )",
+ "success_response_body": "GroupJsonV600(\n group_id = \"group-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Updated Teller Group\",\n group_description = \"Updated description\",\n list_of_roles = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\", \"CanGetTransaction\"),\n is_enabled = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagGroup)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateGroupAtAllBanks, canUpdateGroupAtOneBank))"
+ }
+ },
+ "createUser": {
+ "partial_function_name_raw": "nameOf(createUser)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users\"",
+ "summary": "\"Create User (self-registration)\"",
+ "description": "s\"\"\"Creates OBP user.\n | No authorisation required.\n |\n | Mimics current webform to Register.\n |\n | Requires username(email), password, first_name, last_name, and email.\n |\n | Validation checks performed:\n | - Password must meet strong password requirements (InvalidStrongPasswordFormat error if not)\n | - Username must be unique (409 error if username already exists)\n | - All required fields must be present in valid JSON format\n |\n | Email validation behavior:\n | - Controlled by property 'authUser.skipEmailValidation' (default: false)\n | - When false: User is created with validated=false and a validation email is sent to the user's email address\n | - The validation link is constructed using the `portal_external_url` property which must be set (currently: `${APIUtil.getPropsValue(\"portal_external_url\", \"not set\")}`).\n | - When true: User is created with validated=true and no validation email is sent\n | - Default entitlements are granted immediately regardless of validation status\n |\n | Note: If email validation is required (skipEmailValidation=false), the user must click the validation link\n | in the email before they can log in, even though entitlements are already granted.\n |\n |\"\"\"",
+ "example_request_body": "createUserJsonV600",
+ "success_response_body": "userJsonV200",
+ "error_response_bodies": "List(InvalidJsonFormat, InvalidStrongPasswordFormat, DuplicateUsername, ExternalUserCheckFailed, \"Error occurred during user creation.\", UnknownError)",
+ "tags": "List(apiTagUser, apiTagOnboarding)"
+ },
+ "deleteEntitlement": {
+ "partial_function_name_raw": "nameOf(deleteEntitlement)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/entitlements/ENTITLEMENT_ID\"",
+ "summary": "\"Delete Entitlement\"",
+ "description": "s\"\"\"Delete Entitlement specified by ENTITLEMENT_ID\n |\n |${userAuthenticationMessage(true)}\n |\n |Requires the $canDeleteEntitlementAtAnyBank role.\n |\n |This endpoint is idempotent - if the entitlement does not exist, it returns 204 No Content.\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n EntitlementCannotBeDeleted,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagUser, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteEntitlementAtAnyBank))"
+ }
+ },
+ "getRolesWithEntitlementCountsAtAllBanks": {
+ "partial_function_name_raw": "nameOf(getRolesWithEntitlementCountsAtAllBanks)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/roles-with-entitlement-counts\"",
+ "summary": "\"Get Roles with Entitlement Counts\"",
+ "description": "s\"\"\"Returns all available roles with the count of entitlements that use each role.\n |\n |This endpoint provides statistics about role usage across all banks by counting\n |how many entitlements have been granted for each role.\n |\n |${userAuthenticationMessage(true)}\n |\n |Requires the CanGetRolesWithEntitlementCountsAtAllBanks role.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "RolesWithEntitlementCountsJsonV600(\n roles = List(\n RoleWithEntitlementCountJsonV600(\n role = \"CanGetCustomer\",\n requires_bank_id = true,\n entitlement_count = 5\n ),\n RoleWithEntitlementCountJsonV600(\n role = \"CanGetBank\",\n requires_bank_id = false,\n entitlement_count = 3\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagRole, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetRolesWithEntitlementCountsAtAllBanks))"
+ }
+ },
+ "deleteGroup": {
+ "partial_function_name_raw": "nameOf(deleteGroup)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/groups/GROUP_ID\"",
+ "summary": "\"Delete Group\"",
+ "description": "s\"\"\"Delete a Group.\n |\n |Requires either:\n |- CanDeleteGroupAtAllBanks (for any group)\n |- CanDeleteGroupAtOneBank (for groups at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteGroupAtAllBanks, canDeleteGroupAtOneBank))"
+ }
+ },
+ "addUserToGroup": {
+ "partial_function_name_raw": "nameOf(addUserToGroup)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/group-entitlements\"",
+ "summary": "\"Grant User Membership to Group Entitlements\"",
+ "description": "s\"\"\"Grant the User Group Entitlements.\n |\n |This endpoint creates entitlements for every Role in the Group. If the user\n |already has a particular role at the same bank, that entitlement is skipped (not duplicated).\n |\n |Each entitlement created will have:\n |- group_id set to the group ID\n |- process set to \"GROUP_MEMBERSHIP\"\n |\n |**Response Fields:**\n |- target_entitlements: All roles defined in the group (the complete list of entitlements that this group aims to grant)\n |- entitlements_created: Roles that were newly created as entitlements during this operation\n |- entitlements_skipped: Roles that the user already possessed, so no new entitlement was created\n |\n |Note: target_entitlements = entitlements_created + entitlements_skipped\n |\n |Requires either:\n |- CanAddUserToGroupAtAllBanks (for any group)\n |- CanAddUserToGroupAtOneBank (for groups at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostGroupMembershipJsonV600(\n group_id = \"group-id-123\"\n )",
+ "success_response_body": "AddUserToGroupResponseJsonV600(\n group_id = \"group-id-123\",\n user_id = \"user-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n target_entitlements = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\"),\n entitlements_created = List(\"CanGetCustomer\", \"CanGetAccount\"),\n entitlements_skipped = List(\"CanCreateTransaction\")\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagGroup, apiTagUser, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canAddUserToGroupAtAllBanks, canAddUserToGroupAtOneBank))"
+ }
+ },
+ "getUserGroupMemberships": {
+ "partial_function_name_raw": "nameOf(getUserGroupMemberships)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/group-entitlements\"",
+ "summary": "\"Get User's Group Memberships\"",
+ "description": "s\"\"\"Get all groups a user is a member of.\n |\n |Returns groups where the user has entitlements with process = \"GROUP_MEMBERSHIP\".\n |\n |The response includes:\n |- list_of_entitlements: entitlements the user currently has from this group membership\n |\n |Requires either:\n |- CanGetUserGroupMembershipsAtAllBanks (for any user)\n |- CanGetUserGroupMembershipsAtOneBank (for users at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "UserGroupMembershipsJsonV600(\n group_entitlements = List(\n UserGroupMembershipJsonV600(\n group_id = \"group-id-123\",\n user_id = \"user-id-123\",\n bank_id = Some(\"gh.29.uk\"),\n group_name = \"Teller Group\",\n list_of_entitlements = List(\"CanGetCustomer\", \"CanGetAccount\", \"CanCreateTransaction\")\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup, apiTagUser, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserGroupMembershipsAtAllBanks, canGetUserGroupMembershipsAtOneBank))"
+ }
+ },
+ "getGroupEntitlements": {
+ "partial_function_name_raw": "nameOf(getGroupEntitlements)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/groups/GROUP_ID/entitlements\"",
+ "summary": "\"Get Group Entitlements\"",
+ "description": "s\"\"\"Get all entitlements that have been granted from a specific group.\n |\n |This returns all entitlements where the group_id matches the specified GROUP_ID.\n |\n |Requires:\n |- CanGetEntitlementsForAnyBank\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "GroupEntitlementsJsonV600(\n entitlements = List(\n GroupEntitlementJsonV600(\n entitlement_id = \"entitlement-id-123\",\n role_name = \"CanGetCustomer\",\n bank_id = \"gh.29.uk\",\n user_id = \"user-id-123\",\n username = \"susan.uk.29@example.com\",\n group_id = Some(\"group-id-123\"),\n process = Some(\"GROUP_MEMBERSHIP\")\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetEntitlementsForAnyBank))"
+ }
+ },
+ "removeUserFromGroup": {
+ "partial_function_name_raw": "nameOf(removeUserFromGroup)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/group-entitlements/GROUP_ID\"",
+ "summary": "\"Remove User from Group\"",
+ "description": "s\"\"\"Remove a user from a group. This will delete all entitlements that were created by this group membership.\n |\n |Only removes entitlements with:\n |- group_id matching GROUP_ID\n |- process = \"GROUP_MEMBERSHIP\"\n |\n |Requires either:\n |- CanRemoveUserFromGroupAtAllBanks (for any group)\n |- CanRemoveUserFromGroupAtOneBank (for groups at specific bank)\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagGroup, apiTagUser, apiTagEntitlement)",
+ "extra_named_args": {
+ "roles": "Some(List(canRemoveUserFromGroupAtAllBanks, canRemoveUserFromGroupAtOneBank))"
+ }
+ },
+ "getSystemViews": {
+ "partial_function_name_raw": "nameOf(getSystemViews)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system-views\"",
+ "summary": "\"Get System Views\"",
+ "description": "s\"\"\"Get all system views.\n |\n |System views are predefined views that apply to all accounts, such as:\n |- owner\n |- accountant\n |- auditor\n |- standard\n |\n |Each view is returned with an `allowed_actions` array containing all permissions for that view.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ViewsJsonV600(List(\n ViewJsonV600(\n bank_id = \"\",\n account_id = \"\",\n view_id = \"owner\",\n view_name = \"Owner\",\n description = \"The owner of the account\",\n metadata_view = \"owner\",\n is_public = false,\n is_system = true,\n is_firehose = Some(false),\n alias = \"private\",\n hide_metadata_if_alias_used = false,\n can_grant_access_to_views = List(\"owner\"),\n can_revoke_access_to_views = List(\"owner\"),\n allowed_actions = List(\"can_see_transaction_amount\", \"can_see_bank_account_balance\")\n )\n ))",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView, apiTagView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemViews))"
+ }
+ },
+ "getSystemViewById": {
+ "partial_function_name_raw": "nameOf(getSystemViewById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system-views/VIEW_ID\"",
+ "summary": "\"Get System View\"",
+ "description": "s\"\"\"Get a single system view by its ID.\n |\n |System views are predefined views that apply to all accounts, such as:\n |- owner\n |- accountant\n |- auditor\n |- standard\n |\n |The view is returned with an `allowed_actions` array containing all permissions for that view.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ViewJsonV600(\n bank_id = \"\",\n account_id = \"\",\n view_id = \"owner\",\n view_name = \"Owner\",\n description = \"The owner of the account. Has full privileges.\",\n metadata_view = \"owner\",\n is_public = false,\n is_system = true,\n is_firehose = Some(false),\n alias = \"private\",\n hide_metadata_if_alias_used = false,\n can_grant_access_to_views = List(\"owner\", \"accountant\"),\n can_revoke_access_to_views = List(\"owner\", \"accountant\"),\n allowed_actions = List(\n \"can_see_transaction_amount\",\n \"can_see_bank_account_balance\",\n \"can_add_comment\",\n \"can_create_custom_view\"\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n SystemViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView, apiTagView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemViews))"
+ }
+ },
+ "updateSystemView": {
+ "partial_function_name_raw": "nameOf(updateSystemView)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/system-views/VIEW_ID\"",
+ "summary": "\"Update System View\"",
+ "description": "s\"\"\"Update an existing system view.\n |\n |${userAuthenticationMessage(true)}\n |\n |The JSON sent is the same as during view creation, with one difference: the 'name' field\n |of a view is not editable (it is only set when a view is created).\n |\n |The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n |The response contains the updated view with an `allowed_actions` array.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "UpdateViewJsonV600(\n description = \"This is the owner view\",\n metadata_view = \"owner\",\n is_public = false,\n is_firehose = Some(false),\n which_alias_to_use = \"private\",\n hide_metadata_if_alias_used = false,\n allowed_actions = List(\n \"can_see_transaction_amount\",\n \"can_see_bank_account_balance\",\n \"can_add_comment\"\n ),\n can_grant_access_to_views = Some(List(\"owner\", \"accountant\")),\n can_revoke_access_to_views = Some(List(\"owner\", \"accountant\"))\n )",
+ "success_response_body": "ViewJsonV600(\n bank_id = \"\",\n account_id = \"\",\n view_id = \"owner\",\n view_name = \"Owner\",\n description = \"This is the owner view\",\n metadata_view = \"owner\",\n is_public = false,\n is_system = true,\n is_firehose = Some(false),\n alias = \"private\",\n hide_metadata_if_alias_used = false,\n can_grant_access_to_views = List(\"owner\", \"accountant\"),\n can_revoke_access_to_views = List(\"owner\", \"accountant\"),\n allowed_actions = List(\n \"can_see_transaction_amount\",\n \"can_see_bank_account_balance\",\n \"can_add_comment\"\n )\n )",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n SystemViewNotFound,\n SystemViewCannotBePublicError,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView, apiTagView)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSystemView))"
+ }
+ },
+ "getViewPermissions": {
+ "partial_function_name_raw": "nameOf(getViewPermissions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/view-permissions\"",
+ "summary": "\"Get View Permissions\"",
+ "description": "s\"\"\"Get a list of all available view permissions.\n |\n |This endpoint returns all the available permissions that can be assigned to views,\n |organized by category. These permissions control what actions and data can be accessed\n |through a view.\n |\n |${userAuthenticationMessage(true)}\n |\n |The response contains all available view permission names that can be used in the\n |`allowed_actions` field when creating or updating custom views.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ViewPermissionsJsonV600(\n permissions = List(\n ViewPermissionJsonV600(\"can_see_transaction_amount\", \"Transaction\"),\n ViewPermissionJsonV600(\"can_see_bank_account_balance\", \"Account\"),\n ViewPermissionJsonV600(\"can_create_custom_view\", \"View\")\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagSystemView, apiTagView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetViewPermissionsAtAllBanks))"
+ }
+ },
+ "createCustomViewManagement": {
+ "partial_function_name_raw": "nameOf(createCustomViewManagement)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/views\"",
+ "summary": "\"Create Custom View (Management)\"",
+ "description": "s\"\"\"Create a custom view on a bank account via management endpoint.\n |\n |This is a **management endpoint** that requires the `CanCreateCustomView` role (entitlement).\n |\n |This endpoint provides a simpler, role-based authorization model compared to the original\n |v3.0.0 endpoint which requires view-level permissions. Use this endpoint when you want to\n |grant view creation ability through direct role assignment rather than through view access.\n |\n |For the original endpoint that checks account-level view permissions, see:\n |POST /obp/v3.0.0/banks/BANK_ID/accounts/ACCOUNT_ID/views\n |\n |${userAuthenticationMessage(true)}\n |\n |The 'alias' field in the JSON can take one of three values:\n |\n | * _public_: to use the public alias if there is one specified for the other account.\n | * _private_: to use the private alias if there is one specified for the other account.\n |\n | * _''(empty string)_: to use no alias; the view shows the real name of the other account.\n |\n | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown.\n |\n | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`.\n |\n | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views.\n |\n | You MUST use a leading _ (underscore) in the view name because other view names are reserved for OBP [system views](/index#group-View-System).\n |\n |\"\"\".stripMargin",
+ "example_request_body": "createViewJsonV300",
+ "success_response_body": "viewJsonV300",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n InvalidCustomViewFormat,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomView))"
+ }
+ },
+ "getCustomViews": {
+ "partial_function_name_raw": "nameOf(getCustomViews)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/custom-views\"",
+ "summary": "\"Get Custom Views\"",
+ "description": "s\"\"\"Get all custom views.\n |\n |Custom views are user-created views with names starting with underscore (_), such as:\n |- _work\n |- _personal\n |- _audit\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ViewsJsonV600(List())",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomViews))"
+ }
+ },
+ "getCustomViewById": {
+ "partial_function_name_raw": "nameOf(getCustomViewById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID\"",
+ "summary": "\"Get Custom View\"",
+ "description": "s\"\"\"Get a single custom view by bank, account, and view ID.\n |\n |Custom views are user-created views with names starting with underscore (_), such as:\n |- _work\n |- _personal\n |- _audit\n |\n |Custom views are unique per bank_id, account_id, and view_id combination.\n |\n |The view is returned with an `allowed_actions` array containing all permissions for that view.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ViewJsonV600(\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = \"_work\",\n view_name = \"Work\",\n description = \"A custom view for work-related transactions.\",\n metadata_view = \"_work\",\n is_public = false,\n is_system = false,\n is_firehose = Some(false),\n alias = \"private\",\n hide_metadata_if_alias_used = false,\n can_grant_access_to_views = List(\"_work\"),\n can_revoke_access_to_views = List(\"_work\"),\n allowed_actions = List(\n \"can_see_transaction_amount\",\n \"can_see_bank_account_balance\",\n \"can_add_comment\"\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ViewNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagSystemView)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomViews))"
+ }
+ },
+ "resetPasswordUrl": {
+ "partial_function_name_raw": "nameOf(resetPasswordUrl)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/user/reset-password-url\"",
+ "summary": "\"Create Password Reset URL and Send Email\"",
+ "description": "s\"\"\"Create a password reset URL for a user and automatically send it via email.\n |\n |Authentication is Required.\n |\n |Behavior:\n |- Generates a unique password reset token\n |- Creates a reset URL using the portal_external_url property (falls back to API hostname)\n |- Sends an email to the user with the reset link\n |- Returns the reset URL in the response for logging/tracking purposes\n |\n |Required fields:\n |- username: The user's username (typically email)\n |- email: The user's email address (must match username)\n |- user_id: The user's UUID\n |\n |The user must exist and be validated before a reset URL can be generated.\n |\n |Email configuration must be set up correctly for email delivery to work.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostResetPasswordUrlJsonV600(\n \"user@example.com\",\n \"user@example.com\",\n \"74a8ebcc-10e4-4036-bef3-9835922246bf\"\n )",
+ "success_response_body": "ResetPasswordUrlJsonV600(\n \"https://api.example.com/reset-password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateResetPasswordUrl))"
+ }
+ },
+ "resetPasswordUrlAnonymous": {
+ "partial_function_name_raw": "nameOf(resetPasswordUrlAnonymous)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/password-reset-url\"",
+ "summary": "\"Request Password Reset Email\"",
+ "description": "s\"\"\"Request a password reset email for a user. No authentication is required.\n |\n |Authentication is NOT Required.\n |\n |This endpoint is designed for users who have forgotten their password and cannot log in.\n |\n |Behavior:\n |- Looks up the user by username and email\n |- Generates a unique password reset token\n |- Creates a reset URL using the portal_external_url property (falls back to API hostname)\n |- Sends an email to the user with the reset link\n |\n |Required fields:\n |- username: The user's username (typically email)\n |- email: The user's email address (must match username)\n |\n |The user must exist and be validated before a reset email can be sent.\n |\n |Email configuration must be set up correctly for email delivery to work.\n |\n |Note: For security reasons, this endpoint returns a generic success message regardless of\n |whether the user was found, to prevent user enumeration.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostResetPasswordUrlAnonymousJsonV600(\n \"user@example.com\",\n \"user@example.com\"\n )",
+ "success_response_body": "ResetPasswordUrlAnonymousResponseJsonV600(\n \"If the account exists, a password reset email has been sent.\"\n )",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "resetPasswordComplete": {
+ "partial_function_name_raw": "nameOf(resetPasswordComplete)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/password\"",
+ "summary": "\"Complete Password Reset\"",
+ "description": "s\"\"\"Complete a password reset using the token received via email.\n |\n |Authentication is NOT Required.\n |\n |After requesting a password reset email (via POST /management/user/reset-password-url or\n |POST /users/password-reset-url), the user receives an email with a reset link containing a JWT token.\n |\n |This endpoint accepts that token along with a new password and completes the password reset.\n |\n |The token is a signed JWT with a configurable expiry (default: 120 minutes).\n |Configure the expiry with the property: password_reset_token_expiry_minutes\n |\n |Required fields:\n |- token: The JWT reset token from the password reset email\n |- new_password: The new password (must meet strong password requirements)\n |\n |The token is single-use. Once the password is reset, the token is invalidated.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostResetPasswordCompleteJsonV600(\n \"a1b2c3d4e5f67890abcdef1234567890\",\n \"NewStr0ng!Password\"\n )",
+ "success_response_body": "ResetPasswordCompleteResponseJsonV600(\n \"Password has been reset successfully.\"\n )",
+ "error_response_bodies": "List(\n InvalidJsonFormat,\n InvalidStrongPasswordFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "getWebUiProp": {
+ "partial_function_name_raw": "nameOf(getWebUiProp)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/webui-props/WEBUI_PROP_NAME\"",
+ "summary": "\"Get WebUiProp by Name\"",
+ "description": "s\"\"\"\n |\n |Get a single WebUiProp by name.\n |\n |Properties with names starting with \"webui_\" can be stored in the database and managed via API.\n |\n |**Data Sources:**\n |\n |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.\n |\n |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.\n |\n |**Response Fields:**\n |\n |* `name`: The property name\n |* `value`: The property value\n |* `webUiPropsId` (optional): UUID for database props, omitted for config props\n |* `source`: Either \"database\" (editable via API) or \"config\" (read-only from config file)\n |\n |**Query Parameter:**\n |\n |* `active` (optional, boolean string, default: \"false\")\n | - If `active=false` or omitted: Returns only explicit prop from the database (source=\"database\")\n | - If `active=true`: Returns explicit prop from database, or if not found, returns implicit (default) prop from configuration file (source=\"config\")\n |\n |**Examples:**\n |\n |Get database-stored prop only:\n |${getObpApiRoot}/v6.0.0/webui-props/webui_api_explorer_url\n |\n |Get database prop or fallback to default:\n |${getObpApiRoot}/v6.0.0/webui-props/webui_api_explorer_url?active=true\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"web-ui-props-id\"), Some(\"config\"))",
+ "error_response_bodies": "List(\n WebUiPropsNotFoundByName,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)"
+ },
+ "getWebUiProps": {
+ "partial_function_name_raw": "nameOf(getWebUiProps)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/webui-props\"",
+ "summary": "\"Get WebUiProps\"",
+ "description": "s\"\"\"\n |\n |Get WebUiProps - properties that configure the Web UI behavior and appearance.\n |\n |Properties with names starting with \"webui_\" can be stored in the database and managed via API.\n |\n |**Data Sources:**\n |\n |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database.\n |\n |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file.\n |\n |**Response Fields:**\n |\n |* `name`: The property name\n |* `value`: The property value\n |* `webUiPropsId` (optional): UUID for database props, omitted for config props\n |* `source`: Either \"database\" (editable via API) or \"config\" (read-only from config file)\n |\n |**Query Parameter:**\n |\n |* `what` (optional, string, default: \"active\")\n | - `active`: Returns one value per property name\n | - If property exists in database: returns database value (source=\"database\")\n | - If property only in config file: returns config default value (source=\"config\")\n | - `database`: Returns ONLY properties explicitly stored in the database (source=\"database\")\n | - `config`: Returns ONLY default properties from configuration file (source=\"config\")\n |\n |**Examples:**\n |\n |Get active props (database overrides config, one value per prop):\n |${getObpApiRoot}/v6.0.0/webui-props\n |${getObpApiRoot}/v6.0.0/webui-props?what=active\n |\n |Get only database-stored props:\n |${getObpApiRoot}/v6.0.0/webui-props?what=database\n |\n |Get only default props from configuration:\n |${getObpApiRoot}/v6.0.0/webui-props?what=config\n |\n |For more details about WebUI Props, including how to set config file defaults and precedence order, see ${Glossary.getGlossaryItemLink(\"webui_props\")}.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ListResult(\n \"webui_props\",\n (List(WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"web-ui-props-id\"), Some(\"database\"))))\n )",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)"
+ },
+ "createOrUpdateWebUiProps": {
+ "partial_function_name_raw": "nameOf(createOrUpdateWebUiProps)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/webui_props/WEBUI_PROP_NAME\"",
+ "summary": "\"Create or Update WebUiProps\"",
+ "description": "s\"\"\"Create or Update a WebUiProps.\n |\n |${userAuthenticationMessage(true)}\n |\n |This endpoint is idempotent - it will create the property if it doesn't exist, or update it if it does.\n |The property is identified by WEBUI_PROP_NAME in the URL path.\n |\n |Explanation of Fields:\n |\n |* WEBUI_PROP_NAME in URL path (must start with `webui_`, contain only alphanumeric characters, underscore, and dot, not exceed 255 characters, and will be converted to lowercase)\n |* value is required String value in request body\n |\n |The line break and double quotations should be escaped, example:\n |\n |```\n |\n |{\"name\": \"webui_some\", \"value\": \"this value\n |have \"line break\" and double quotations.\"}\n |\n |```\n |should be escaped like this:\n |\n |```\n |\n |{\"name\": \"webui_some\", \"value\": \"this value\\\\nhave \\\\\"line break\\\\\" and double quotations.\"}\n |\n |```\n |\n |Insert image examples:\n |\n |```\n |// set width=100 and height=50\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |// only set height=50\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |// only width=20%\n |{\"name\": \"webui_some_pic\", \"value\": \"here is a picture \"}\n |\n |```\n |\n |\"\"\"",
+ "example_request_body": "WebUiPropsPutJsonV600(\"https://apiexplorer.openbankproject.com\")",
+ "success_response_body": "WebUiPropsCommons(\"webui_api_explorer_url\", \"https://apiexplorer.openbankproject.com\", Some(\"some-web-ui-props-id\"))",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n InvalidWebUiProps,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateWebUiProps))"
+ }
+ },
+ "deleteWebUiProps": {
+ "partial_function_name_raw": "nameOf(deleteWebUiProps)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/webui_props/WEBUI_PROP_NAME\"",
+ "summary": "\"Delete WebUiProps\"",
+ "description": "s\"\"\"Delete a WebUiProps specified by WEBUI_PROP_NAME.\n |\n |${userAuthenticationMessage(true)}\n |\n |The property name will be converted to lowercase before deletion.\n |\n |Returns 204 No Content on successful deletion.\n |\n |This endpoint is idempotent - if the property does not exist, it still returns 204 No Content.\n |\n |Requires the $canDeleteWebUiProps role.\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidWebUiProps,\n UnknownError\n )",
+ "tags": "List(apiTagWebUiProps)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteWebUiProps))"
+ }
+ },
+ "getSystemDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getSystemDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/system-dynamic-entities\"",
+ "summary": "\"Get System Dynamic Entities\"",
+ "description": "s\"\"\"Get all System Dynamic Entities with record counts.\n |\n |Each dynamic entity in the response includes a `record_count` field showing how many data records exist for that entity.\n |\n |This v6.0.0 endpoint returns snake_case field names and an explicit `entity_name` field.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )} \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DynamicEntitiesWithCountJsonV600(\n dynamic_entities = List(\n DynamicEntityDefinitionWithCountJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\"}, \"language\": {\"type\": \"string\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject],\n record_count = 42\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSystemLevelDynamicEntities))"
+ }
+ },
+ "getBankLevelDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getBankLevelDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities\"",
+ "summary": "\"Get Bank Level Dynamic Entities\"",
+ "description": "s\"\"\"Get all Bank Level Dynamic Entities for one bank with record counts.\n |\n |Each dynamic entity in the response includes a `record_count` field showing how many data records exist for that entity.\n |\n |This v6.0.0 endpoint returns snake_case field names and an explicit `entity_name` field.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )} \"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DynamicEntitiesWithCountJsonV600(\n dynamic_entities = List(\n DynamicEntityDefinitionWithCountJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = Some(\"gh.29.uk\"),\n has_personal_entity = true,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\"}, \"language\": {\"type\": \"string\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject],\n record_count = 42\n )\n )\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities))"
+ }
+ },
+ "createSystemDynamicEntity": {
+ "partial_function_name_raw": "nameOf(createSystemDynamicEntity)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/system-dynamic-entities\"",
+ "summary": "\"Create System Level Dynamic Entity\"",
+ "description": "s\"\"\"Create a system level Dynamic Entity.\n |\n |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.\n |\n |**Request format:**\n |```json\n |{\n | \"entity_name\": \"customer_preferences\",\n | \"has_personal_entity\": true,\n | \"has_public_access\": false,\n | \"has_community_access\": false,\n | \"personal_requires_role\": false,\n | \"schema\": {\n | \"description\": \"User preferences\",\n | \"required\": [\"theme\"],\n | \"properties\": {\n | \"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"},\n | \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}\n | }\n | }\n |}\n |```\n |\n |**Note:**\n |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.\n |* Each property MUST include an `example` field with a valid example value.\n |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.\n |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.\n |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).\n |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "CreateDynamicEntityRequestJsonV600(\n entity_name = \"customer_preferences\",\n has_personal_entity = Some(true),\n has_public_access = Some(false),\n has_community_access = Some(false),\n personal_requires_role = Some(false),\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n has_public_access = false,\n has_community_access = false,\n personal_requires_role = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canCreateSystemLevelDynamicEntity))"
+ }
+ },
+ "createBankLevelDynamicEntity": {
+ "partial_function_name_raw": "nameOf(createBankLevelDynamicEntity)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities\"",
+ "summary": "\"Create Bank Level Dynamic Entity\"",
+ "description": "s\"\"\"Create a bank level Dynamic Entity.\n |\n |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.\n |\n |**Request format:**\n |```json\n |{\n | \"entity_name\": \"customer_preferences\",\n | \"has_personal_entity\": true,\n | \"has_public_access\": false,\n | \"has_community_access\": false,\n | \"personal_requires_role\": false,\n | \"schema\": {\n | \"description\": \"User preferences\",\n | \"required\": [\"theme\"],\n | \"properties\": {\n | \"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"},\n | \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}\n | }\n | }\n |}\n |```\n |\n |**Note:**\n |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.\n |* Each property MUST include an `example` field with a valid example value.\n |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.\n |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.\n |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).\n |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "CreateDynamicEntityRequestJsonV600(\n entity_name = \"customer_preferences\",\n has_personal_entity = Some(true),\n has_public_access = Some(false),\n has_community_access = Some(false),\n personal_requires_role = Some(false),\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = Some(\"gh.29.uk\"),\n has_personal_entity = true,\n has_public_access = false,\n has_community_access = false,\n personal_requires_role = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateBankLevelDynamicEntity, canCreateAnyBankLevelDynamicEntity))"
+ }
+ },
+ "updateSystemDynamicEntity": {
+ "partial_function_name_raw": "nameOf(updateSystemDynamicEntity)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/system-dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Update System Level Dynamic Entity\"",
+ "description": "s\"\"\"Update a system level Dynamic Entity.\n |\n |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.\n |\n |**Request format:**\n |```json\n |{\n | \"entity_name\": \"customer_preferences\",\n | \"has_personal_entity\": true,\n | \"has_public_access\": false,\n | \"has_community_access\": false,\n | \"personal_requires_role\": false,\n | \"schema\": {\n | \"description\": \"User preferences updated\",\n | \"required\": [\"theme\"],\n | \"properties\": {\n | \"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"},\n | \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"},\n | \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}\n | }\n | }\n |}\n |```\n |\n |**Note:**\n |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.\n |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.\n |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.\n |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).\n |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "UpdateDynamicEntityRequestJsonV600(\n entity_name = \"customer_preferences\",\n has_personal_entity = Some(true),\n has_public_access = Some(false),\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n has_public_access = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSystemDynamicEntity))"
+ }
+ },
+ "updateBankLevelDynamicEntity": {
+ "partial_function_name_raw": "nameOf(updateBankLevelDynamicEntity)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Update Bank Level Dynamic Entity\"",
+ "description": "s\"\"\"Update a bank level Dynamic Entity.\n |\n |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.\n |\n |**Request format:**\n |```json\n |{\n | \"entity_name\": \"customer_preferences\",\n | \"has_personal_entity\": true,\n | \"has_public_access\": false,\n | \"has_community_access\": false,\n | \"personal_requires_role\": false,\n | \"schema\": {\n | \"description\": \"User preferences updated\",\n | \"required\": [\"theme\"],\n | \"properties\": {\n | \"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"},\n | \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"},\n | \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}\n | }\n | }\n |}\n |```\n |\n |**Note:**\n |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.\n |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.\n |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.\n |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).\n |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "UpdateDynamicEntityRequestJsonV600(\n entity_name = \"customer_preferences\",\n has_personal_entity = Some(true),\n has_public_access = Some(false),\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = Some(\"gh.29.uk\"),\n has_personal_entity = true,\n has_public_access = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateBankLevelDynamicEntity))"
+ }
+ },
+ "updateMyDynamicEntity": {
+ "partial_function_name_raw": "nameOf(updateMyDynamicEntity)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/my/dynamic-entities/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Update My Dynamic Entity\"",
+ "description": "s\"\"\"Update a Dynamic Entity that I created.\n |\n |This v6.0.0 endpoint accepts and returns snake_case field names with an explicit `entity_name` field.\n |\n |**Request format:**\n |```json\n |{\n | \"entity_name\": \"customer_preferences\",\n | \"has_personal_entity\": true,\n | \"has_public_access\": false,\n | \"has_community_access\": false,\n | \"personal_requires_role\": false,\n | \"schema\": {\n | \"description\": \"User preferences updated\",\n | \"required\": [\"theme\"],\n | \"properties\": {\n | \"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"},\n | \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"},\n | \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}\n | }\n | }\n |}\n |```\n |\n |**Note:**\n |* The `entity_name` must be lowercase with underscores (snake_case), e.g. `customer_preferences`. No uppercase letters or spaces allowed.\n |* Each property can optionally include `description` (markdown text), and for string types: `minLength` and `maxLength`.\n |* Set `has_public_access` to `true` to generate read-only public endpoints (GET only, no authentication required) under `/public/`.\n |* Set `has_community_access` to `true` to generate read-only community endpoints (GET only, authentication required + CanGet role) under `/community/`. Community endpoints return ALL records (personal + non-personal from all users).\n |* Set `personal_requires_role` to `true` to require the corresponding role (e.g. CanCreateDynamicEntity_, CanGetDynamicEntity_) for `/my/` personal entity endpoints. Default is `false` (any authenticated user can use `/my/` endpoints).\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"My-Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "UpdateDynamicEntityRequestJsonV600(\n entity_name = \"customer_preferences\",\n has_personal_entity = Some(true),\n has_public_access = Some(false),\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n has_public_access = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences updated\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 20, \"example\": \"dark\", \"description\": \"The UI theme preference\"}, \"language\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 5, \"example\": \"en\", \"description\": \"ISO language code\"}, \"notifications_enabled\": {\"type\": \"boolean\", \"example\": \"true\", \"description\": \"Whether to send notifications\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)"
+ },
+ "deleteSystemDynamicEntityCascade": {
+ "partial_function_name_raw": "nameOf(deleteSystemDynamicEntityCascade)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/system-dynamic-entities/cascade/DYNAMIC_ENTITY_ID\"",
+ "summary": "\"Delete System Level Dynamic Entity Cascade\"",
+ "description": "s\"\"\"Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID and all its data records.\n |\n |This endpoint performs a cascade delete:\n |1. Automatically backs up the entity definition and all data records to a ZZ_BAK_ prefixed entity (e.g. my_entity is backed up to ZZ_BAK_my_entity). If a previous ZZ_BAK_ backup exists, it is overwritten.\n |2. Deletes all data records associated with the dynamic entity\n |3. Deletes the dynamic entity definition itself\n |\n |Note: Entities whose name already starts with ZZ_BAK_ are not backed up again (to avoid infinite backup chains).\n |\n |This operation is only allowed for non-personal entities (hasPersonalEntity=false).\n |For personal entities (hasPersonalEntity=true), you must delete the records and definition separately.\n |\n |\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"Dynamic-Entities\"\n )}/\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCascadeSystemDynamicEntity))"
+ }
+ },
+ "createAbacRule": {
+ "partial_function_name_raw": "nameOf(createAbacRule)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/abac-rules\"",
+ "summary": "\"Create ABAC Rule\"",
+ "description": "s\"\"\"Create a new ABAC (Attribute-Based Access Control) rule.\n |\n |ABAC rules are Scala functions that return a Boolean value indicating whether access should be granted.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Testing_Examples\")} - Testing examples and patterns\n |\n |The rule function receives 18 parameters including authenticatedUser, attributes, auth context, and optional objects (bank, account, transaction, etc.).\n |\n |Example rule code:\n |```scala\n |// Allow access only if authenticated user is admin\n |authenticatedUser.emailAddress.contains(\"admin\")\n |```\n |\n |```scala\n |// Allow access only to accounts with balance > 1000\n |accountOpt.exists(_.balance.toDouble > 1000.0)\n |```\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "CreateAbacRuleJsonV600(\n rule_name = \"admin_only\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\")\"\"\",\n description = \"Only allow access to users with admin email\",\n policy = \"user-access,admin\",\n is_active = true\n )",
+ "success_response_body": "AbacRuleJsonV600(\n abac_rule_id = \"abc123\",\n rule_name = \"admin_only\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\")\"\"\",\n is_active = true,\n description = \"Only allow access to users with admin email\",\n policy = \"user-access,admin\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user123\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAbacRule))"
+ }
+ },
+ "getAbacRule": {
+ "partial_function_name_raw": "nameOf(getAbacRule)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/abac-rules/ABAC_RULE_ID\"",
+ "summary": "\"Get ABAC Rule\"",
+ "description": "s\"\"\"Get an ABAC rule by its ID.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "AbacRuleJsonV600(\n abac_rule_id = \"abc123\",\n rule_name = \"admin_only\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\")\"\"\",\n is_active = true,\n description = \"Only allow access to users with admin email\",\n policy = \"user-access,admin\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user123\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAbacRule))"
+ }
+ },
+ "getAbacRules": {
+ "partial_function_name_raw": "nameOf(getAbacRules)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/abac-rules\"",
+ "summary": "\"Get ABAC Rules\"",
+ "description": "s\"\"\"Get all ABAC rules.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "AbacRulesJsonV600(\n abac_rules = List(\n AbacRuleJsonV600(\n abac_rule_id = \"abc123\",\n rule_name = \"admin_only\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\")\"\"\",\n is_active = true,\n description = \"Only allow access to users with admin email\",\n policy = \"user-access,admin\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user123\"\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAbacRule))"
+ }
+ },
+ "getAbacRulesByPolicy": {
+ "partial_function_name_raw": "nameOf(getAbacRulesByPolicy)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/abac-rules/policy/POLICY\"",
+ "summary": "\"Get ABAC Rules by Policy\"",
+ "description": "s\"\"\"Get all ABAC rules that belong to a specific policy.\n |\n |Multiple rules can share the same policy. Rules with multiple policies (comma-separated)\n |will be returned if any of their policies match the requested policy.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "AbacRulesJsonV600(\n abac_rules = List(\n AbacRuleJsonV600(\n abac_rule_id = \"abc123\",\n rule_name = \"admin_only\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\")\"\"\",\n is_active = true,\n description = \"Only allow access to users with admin email\",\n policy = \"user-access,admin\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user123\"\n ),\n AbacRuleJsonV600(\n abac_rule_id = \"def456\",\n rule_name = \"admin_department_check\",\n rule_code = \"\"\"user.department == \"admin\"\"\"\",\n is_active = true,\n description = \"Check if user is in admin department\",\n policy = \"admin\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user123\"\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAbacRule))"
+ }
+ },
+ "updateAbacRule": {
+ "partial_function_name_raw": "nameOf(updateAbacRule)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/abac-rules/ABAC_RULE_ID\"",
+ "summary": "\"Update ABAC Rule\"",
+ "description": "s\"\"\"Update an existing ABAC rule.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "UpdateAbacRuleJsonV600(\n rule_name = \"admin_only_updated\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\") && user.provider == \"obp\"\"\"\",\n description = \"Only allow access to OBP admin users\",\n policy = \"user-access,admin,obp\",\n is_active = true\n )",
+ "success_response_body": "AbacRuleJsonV600(\n abac_rule_id = \"abc123\",\n rule_name = \"admin_only_updated\",\n rule_code = \"\"\"user.emailAddress.contains(\"admin\") && user.provider == \"obp\"\"\"\",\n is_active = true,\n description = \"Only allow access to OBP admin users\",\n policy = \"user-access,admin,obp\",\n created_by_user_id = \"user123\",\n updated_by_user_id = \"user456\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAbacRule))"
+ }
+ },
+ "deleteAbacRule": {
+ "partial_function_name_raw": "nameOf(deleteAbacRule)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/abac-rules/ABAC_RULE_ID\"",
+ "summary": "\"Delete ABAC Rule\"",
+ "description": "s\"\"\"Delete an ABAC rule by its ID.\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteAbacRule))"
+ }
+ },
+ "getAbacRuleSchema": {
+ "partial_function_name_raw": "nameOf(getAbacRuleSchema)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/abac-rules-schema\"",
+ "summary": "\"Get ABAC Rule Schema\"",
+ "description": "s\"\"\"Get schema information about ABAC rule structure for building rule code.\n |\n |This endpoint returns schema information including:\n |- All 18 parameters available in ABAC rules\n |- Object types (User, Bank, Account, etc.) and their properties\n |- Available operators and syntax\n |- Example rules\n |\n |This schema information is useful for:\n |- Building rule editors with auto-completion\n |- Validating rule syntax in frontends\n |- AI agents that help construct rules\n |- Dynamic form builders\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "AbacRuleSchemaJsonV600(\n parameters = List(\n AbacParameterJsonV600(\n name = \"authenticatedUser\",\n `type` = \"User\",\n description = \"The logged-in user (always present)\",\n required = true,\n category = \"User\"\n )\n ),\n object_types = List(\n AbacObjectTypeJsonV600(\n name = \"User\",\n description = \"User object with profile information\",\n properties = List(\n AbacObjectPropertyJsonV600(\n name = \"userId\",\n `type` = \"String\",\n description = \"Unique user ID\"\n )\n )\n )\n ),\n examples = List(\n AbacRuleExampleJsonV600(\n rule_name = \"Check User Identity\",\n rule_code = \"authenticatedUser.userId == user.userId\",\n description = \"Verify that the authenticated user matches the target user\",\n policy = \"user-access\",\n is_active = true\n ),\n AbacRuleExampleJsonV600(\n rule_name = \"Check Specific Bank\",\n rule_code = \"bankOpt.isDefined && bankOpt.get.bankId.value == \\\"gh.29.uk\\\"\",\n policy = \"bank-access\",\n description = \"Verify that the bank context is defined and matches a specific bank ID\",\n is_active = true\n )\n ),\n available_operators = List(\"==\", \"!=\", \"&&\", \"||\", \"!\", \">\", \"<\", \">=\", \"<=\", \"contains\", \"isDefined\"),\n notes = List(\n \"Only authenticatedUser is guaranteed to exist (not wrapped in Option)\",\n \"All other objects are Option types - use isDefined or pattern matching\",\n \"Attributes are Lists - use .find(), .exists(), .forall() etc.\"\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAbacRule))"
+ }
+ },
+ "getAbacPolicies": {
+ "partial_function_name_raw": "nameOf(getAbacPolicies)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/abac-policies\"",
+ "summary": "\"Get ABAC Policies\"",
+ "description": "s\"\"\"Get the list of allowed ABAC policy names.\n |\n |ABAC rules are organized by policies. Each rule must have at least one policy assigned.\n |Rules can have multiple policies (comma-separated). This endpoint returns the list of\n |standardized policy names that should be used when creating or updating rules.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "AbacPoliciesJsonV600(\n policies = List(\n AbacPolicyJsonV600(\n policy = \"account-access\",\n description = \"Rules for controlling access to account information\"\n )\n )\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAbacRule))"
+ }
+ },
+ "validateAbacRule": {
+ "partial_function_name_raw": "nameOf(validateAbacRule)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/abac-rules/validate\"",
+ "summary": "\"Validate ABAC Rule\"",
+ "description": "s\"\"\"Validate ABAC rule code syntax and structure without creating or executing the rule.\n |\n |This endpoint performs the following validations:\n |- Parse the rule_code as a Scala expression\n |- Validate syntax - check for parsing errors\n |- Validate field references - check if referenced objects/fields exist\n |- Check type consistency - verify the expression returns a Boolean\n |\n |**Available ABAC Context Objects:**\n |- AuthenticatedUser - The user who is logged in\n |- OnBehalfOfUser - Optional delegation user\n |- User - Target user being evaluated\n |- Bank, Account, View, Transaction, TransactionRequest, Customer\n |- Attributes for each entity (e.g., userAttributes, accountAttributes)\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |\n |This is a \"dry-run\" validation that does NOT save or execute the rule.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "ValidateAbacRuleJsonV600(\n rule_code = \"\"\"AuthenticatedUser.user_id == Account.owner_id\"\"\"\n )",
+ "success_response_body": "ValidateAbacRuleSuccessJsonV600(\n valid = true,\n message = \"ABAC rule code is valid\"\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAbacRule))"
+ }
+ },
+ "validateDynamicResourceDoc": {
+ "partial_function_name_raw": "nameOf(validateDynamicResourceDoc)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/dynamic-resource-docs/validate\"",
+ "summary": "\"Validate Dynamic Resource Doc\"",
+ "description": "s\"\"\"Dry-run validation of a Dynamic Resource Doc. Send the same payload you would send to `Create Dynamic Resource Doc` and this endpoint will:\n |\n |- Parse `method_body` (URL-decoded) as Scala code and run the ToolBox compiler against it, wrapped in the same template used at runtime (request/response case classes generated from `example_request_body` / `success_response_body`).\n |- Run the OBP compilation-dependency guard (when the OBP prop `dynamic_code_compile_validate_enable` is set to `true`).\n |\n |Always returns HTTP 200. Inspect the `valid` field in the response:\n |\n |* `true` — the Scala compiles and all referenced OBP methods are on the allowlist.\n |* `false` — the response includes `error` (raw compiler / guard message), `message` (OBP error constant) and `details.error_type` — one of:\n | * `CompilationError` — `method_body` failed to compile.\n | * `DependencyError` — compiled, but references OBP types/methods that the admin has not allowed in `dynamic_code_compile_validate_dependencies`.\n | * `UnknownError` — any other unexpected exception.\n |\n |Nothing is persisted and no endpoint is served as a result of calling this.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "jsonDynamicResourceDoc.copy(dynamicResourceDocId = None)",
+ "success_response_body": "ValidateDynamicResourceDocSuccessJsonV600(\n valid = true,\n message = \"Dynamic Resource Doc method body is valid Scala and uses allowed dependencies.\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicResourceDoc)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateDynamicResourceDoc))"
+ }
+ },
+ "executeAbacRule": {
+ "partial_function_name_raw": "nameOf(executeAbacRule)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/abac-rules/ABAC_RULE_ID/execute\"",
+ "summary": "\"Execute ABAC Rule\"",
+ "description": "s\"\"\"Execute an ABAC rule to test access control.\n |\n |This endpoint allows you to test an ABAC rule with specific context (authenticated user, bank, account, transaction, customer, etc.).\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Testing_Examples\")} - Testing examples and patterns\n |\n |You can provide optional IDs in the request body to test the rule with specific context.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "ExecuteAbacRuleJsonV600(\n authenticated_user_id = Some(\"c7b6cb47-cb96-4441-8801-35b57456753a\"),\n on_behalf_of_user_id = Some(\"a3b5c123-1234-5678-9012-fedcba987654\"),\n user_id = Some(\"c7b6cb47-cb96-4441-8801-35b57456753a\"),\n bank_id = Some(\"gh.29.uk\"),\n account_id = Some(\"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\"),\n view_id = Some(\"owner\"),\n transaction_request_id = Some(\"123456\"),\n transaction_id = Some(\"abc123\"),\n customer_id = Some(\"customer-id-123\")\n )",
+ "success_response_body": "AbacRuleResultJsonV600(\n result = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canExecuteAbacRule))"
+ }
+ },
+ "executeAbacPolicy": {
+ "partial_function_name_raw": "nameOf(executeAbacPolicy)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/abac-policies/POLICY/execute\"",
+ "summary": "\"Execute ABAC Policy\"",
+ "description": "s\"\"\"Execute all ABAC rules in a policy to test access control.\n |\n |This endpoint executes all active rules that belong to the specified policy.\n |The policy uses OR logic - access is granted if at least one rule passes.\n |\n |This allows you to test a complete policy with specific context (authenticated user, bank, account, transaction, customer, etc.).\n |\n |**Documentation:**\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Simple_Guide\")} - Getting started with ABAC rules\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Parameters_Summary\")} - Complete list of all 18 parameters\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Object_Properties_Reference\")} - Detailed property reference\n |- ${Glossary.getGlossaryItemLink(\"ABAC_Testing_Examples\")} - Testing examples and patterns\n |\n |You can provide optional IDs in the request body to test the policy with specific context.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "ExecuteAbacRuleJsonV600(\n authenticated_user_id = Some(\"c7b6cb47-cb96-4441-8801-35b57456753a\"),\n on_behalf_of_user_id = Some(\"a3b5c123-1234-5678-9012-fedcba987654\"),\n user_id = Some(\"c7b6cb47-cb96-4441-8801-35b57456753a\"),\n bank_id = Some(\"gh.29.uk\"),\n account_id = Some(\"8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0\"),\n view_id = Some(\"owner\"),\n transaction_request_id = Some(\"123456\"),\n transaction_id = Some(\"abc123\"),\n customer_id = Some(\"customer-id-123\")\n )",
+ "success_response_body": "AbacRuleResultJsonV600(\n result = true\n )",
+ "error_response_bodies": "List(\n AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagABAC)",
+ "extra_named_args": {
+ "roles": "Some(List(canExecuteAbacRule))"
+ }
+ },
+ "createUserAttribute": {
+ "partial_function_name_raw": "nameOf(createUserAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/USER_ID/attributes\"",
+ "summary": "\"Create User Attribute\"",
+ "description": "s\"\"\"Create a User Attribute for the user specified by USER_ID.\n |\n |User Attributes are non-personal attributes (IsPersonal=false) that can be used in ABAC rules.\n |They require a role to set, similar to Customer Attributes, Account Attributes, etc.\n |\n |For personal attributes that users manage themselves, see the /my/personal-data-fields endpoints.\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or \"DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "code.api.v5_1_0.UserAttributeJsonV510(\n name = \"account_type\",\n `type` = \"STRING\",\n value = \"premium\"\n )",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateUserAttribute))"
+ }
+ },
+ "getUserAttributes": {
+ "partial_function_name_raw": "nameOf(getUserAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/attributes\"",
+ "summary": "\"Get User Attributes\"",
+ "description": "s\"\"\"Get User Attributes for the user specified by USER_ID.\n |\n |Returns non-personal user attributes (IsPersonal=false) that can be used in ABAC rules.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "code.api.v5_1_0.UserAttributesResponseJsonV510(\n user_attributes = List(userAttributeResponseJsonV510)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserAttributes))"
+ }
+ },
+ "getUserAttributeById": {
+ "partial_function_name_raw": "nameOf(getUserAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/USER_ID/attributes/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Get User Attribute By Id\"",
+ "description": "s\"\"\"Get a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n UserAttributeNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetUserAttributes))"
+ }
+ },
+ "updateUserAttribute": {
+ "partial_function_name_raw": "nameOf(updateUserAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/users/USER_ID/attributes/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Update User Attribute\"",
+ "description": "s\"\"\"Update a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "code.api.v5_1_0.UserAttributeJsonV510(\n name = \"account_type\",\n `type` = \"STRING\",\n value = \"enterprise\"\n )",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n UserAttributeNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateUserAttribute))"
+ }
+ },
+ "deleteUserAttribute": {
+ "partial_function_name_raw": "nameOf(deleteUserAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/users/USER_ID/attributes/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Delete User Attribute\"",
+ "description": "s\"\"\"Delete a User Attribute by USER_ATTRIBUTE_ID for the user specified by USER_ID.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UserNotFoundByUserId,\n UserAttributeNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteUserAttribute))"
+ }
+ },
+ "createPersonalDataField": {
+ "partial_function_name_raw": "nameOf(createPersonalDataField)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/my/personal-data-fields\"",
+ "summary": "\"Create Personal Data Field\"",
+ "description": "s\"\"\"Create a Personal Data Field for the currently authenticated user.\n |\n |Personal Data Fields (IsPersonal=true) are managed by the user themselves and do not require special roles.\n |This data is not available in ABAC rules for privacy reasons.\n |\n |For non-personal attributes that can be used in ABAC rules, see the /users/USER_ID/attributes endpoints.\n |\n |The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or \"DATE_WITH_DAY\"\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "code.api.v5_1_0.UserAttributeJsonV510(\n name = \"favorite_color\",\n `type` = \"STRING\",\n value = \"blue\"\n )",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "getPersonalDataFields": {
+ "partial_function_name_raw": "nameOf(getPersonalDataFields)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/personal-data-fields\"",
+ "summary": "\"Get Personal Data Fields\"",
+ "description": "s\"\"\"Get Personal Data Fields for the currently authenticated user.\n |\n |Returns Personal Data Fields (IsPersonal=true) that are managed by the user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "code.api.v5_1_0.UserAttributesResponseJsonV510(\n user_attributes = List(userAttributeResponseJsonV510)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "getPersonalDataFieldById": {
+ "partial_function_name_raw": "nameOf(getPersonalDataFieldById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/personal-data-fields/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Get Personal Data Field By Id\"",
+ "description": "s\"\"\"Get a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserAttributeNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "updatePersonalDataField": {
+ "partial_function_name_raw": "nameOf(updatePersonalDataField)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/my/personal-data-fields/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Update Personal Data Field\"",
+ "description": "s\"\"\"Update a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "code.api.v5_1_0.UserAttributeJsonV510(\n name = \"favorite_color\",\n `type` = \"STRING\",\n value = \"green\"\n )",
+ "success_response_body": "userAttributeResponseJsonV510",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserAttributeNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "deletePersonalDataField": {
+ "partial_function_name_raw": "nameOf(deletePersonalDataField)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/my/personal-data-fields/USER_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Personal Data Field\"",
+ "description": "s\"\"\"Delete a Personal Data Field by USER_ATTRIBUTE_ID for the currently authenticated user.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserAttributeNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagUser, apiTagUserAttribute, apiTagAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "getMessageDocsJsonSchema": {
+ "partial_function_name_raw": "nameOf(getMessageDocsJsonSchema)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/message-docs/CONNECTOR/json-schema\"",
+ "summary": "\"Get Message Docs as JSON Schema\"",
+ "description": "\"\"\"Returns message documentation as JSON Schema format for code generation in any language.\n |\n |This endpoint provides machine-readable schemas instead of just examples, making it ideal for:\n |- AI-powered code generation\n |- Automatic adapter creation in multiple languages\n |- Type-safe client generation with tools like quicktype\n |\n |**Supported Connectors:**\n |- rabbitmq_vOct2024 - RabbitMQ connector message schemas\n |- rest_vMar2019 - REST connector message schemas\n |- akka_vDec2018 - Akka connector message schemas\n |- kafka_vMay2019 - Kafka connector message schemas (if available)\n |\n |**Code Generation Examples:**\n |\n |Generate Scala code with Circe:\n |```bash\n |curl https://api.../message-docs/rabbitmq_vOct2024/json-schema > schemas.json\n |quicktype -s schema schemas.json -o Messages.scala --framework circe\n |```\n |\n |Generate Python code:\n |```bash\n |quicktype -s schema schemas.json -o messages.py --lang python\n |```\n |\n |Generate TypeScript code:\n |```bash\n |quicktype -s schema schemas.json -o messages.ts --lang typescript\n |```\n |\n |**Schema Structure:**\n |Each message includes:\n |- `process` - The connector method name (e.g., \"obp.getAdapterInfo\")\n |- `description` - Human-readable description of what the message does\n |- `outbound_schema` - JSON Schema for request messages (OBP-API -> Adapter)\n |- `inbound_schema` - JSON Schema for response messages (Adapter -> OBP-API)\n |\n |All nested type definitions are included in the `definitions` section for reuse.\n |\n |**Authentication:**\n |This endpoint is publicly accessible (no authentication required) to facilitate adapter development.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n InvalidConnector,\n UnknownError\n )",
+ "tags": "List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)"
+ },
+ "getMyDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getMyDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/dynamic-entities\"",
+ "summary": "\"Get My Dynamic Entities\"",
+ "description": "s\"\"\"Get all Dynamic Entity definitions I created.\n |\n |This v6.0.0 endpoint returns a cleaner response format with:\n |* snake_case field names (dynamic_entity_id, user_id, bank_id, has_personal_entity)\n |* An explicit entity_name field instead of using the entity name as a dynamic JSON key\n |* The entity schema in a separate definition object\n |\n |For more information see ${Glossary.getGlossaryItemLink(\n \"My-Dynamic-Entities\"\n )}\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MyDynamicEntitiesJsonV600(\n dynamic_entities = List(\n DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\"}, \"language\": {\"type\": \"string\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject],\n _links = Some(DynamicEntityLinksJsonV600(\n related = List(\n RelatedLinkJsonV600(\"personal-list\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences\", \"GET\"),\n RelatedLinkJsonV600(\"personal-create\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences\", \"POST\"),\n RelatedLinkJsonV600(\"personal-read\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"GET\"),\n RelatedLinkJsonV600(\"personal-update\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"PUT\"),\n RelatedLinkJsonV600(\"personal-delete\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"DELETE\")\n )\n ))\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)"
+ },
+ "getAvailablePersonalDynamicEntities": {
+ "partial_function_name_raw": "nameOf(getAvailablePersonalDynamicEntities)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/personal-dynamic-entities/available\"",
+ "summary": "\"Get Available Personal Dynamic Entities\"",
+ "description": "s\"\"\"Get all Dynamic Entities that support personal data storage (hasPersonalEntity == true).\n |\n |This endpoint allows regular users (without admin roles) to discover which dynamic entities\n |they can interact with for storing personal data via the /my/ENTITY_NAME endpoints.\n |\n |Authentication: User must be logged in (no special roles required).\n |\n |Use case: Portals and apps can show users what personal data types are available\n |without needing admin access to view all dynamic entity definitions.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"My-Dynamic-Entities\")}\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MyDynamicEntitiesJsonV600(\n dynamic_entities = List(\n DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"customer_preferences\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = true,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"User preferences\", \"required\": [\"theme\"], \"properties\": {\"theme\": {\"type\": \"string\"}, \"language\": {\"type\": \"string\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject],\n _links = Some(DynamicEntityLinksJsonV600(\n related = List(\n RelatedLinkJsonV600(\"personal-list\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences\", \"GET\"),\n RelatedLinkJsonV600(\"personal-create\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences\", \"POST\"),\n RelatedLinkJsonV600(\"personal-read\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"GET\"),\n RelatedLinkJsonV600(\"personal-update\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"PUT\"),\n RelatedLinkJsonV600(\"personal-delete\", s\"/obp/${ApiVersion.`dynamic-entity`}/my/customer_preferences/CUSTOMER_PREFERENCES_ID\", \"DELETE\")\n )\n ))\n )\n )\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagDynamicEntity, apiTagPersonalDynamicEntity, apiTagApi)"
+ },
+ "verifyUserCredentials": {
+ "partial_function_name_raw": "nameOf(verifyUserCredentials)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/users/verify-credentials\"",
+ "summary": "\"Verify User Credentials\"",
+ "description": "s\"\"\"Verify a user's credentials (username, password, provider) and return user information if valid.\n |\n |This endpoint validates the provided credentials without creating a token or session.\n |It can be used to verify user credentials in external systems.\n |\n |${applicationAccessMessage(true)}\n |\n |\"\"\"",
+ "example_request_body": "PostVerifyUserCredentialsJsonV600(\n username = \"username\",\n password = \"password\",\n provider = Constant.localIdentityProvider\n )",
+ "success_response_body": "userJsonV200",
+ "error_response_bodies": "List(\n UserHasMissingRoles,\n InvalidJsonFormat,\n InvalidLoginCredentials,\n UsernameHasBeenLocked,\n UnknownError\n )",
+ "tags": "List(apiTagUser)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canVerifyUserCredentials))"
+ }
+ },
+ "verifyOidcClient": {
+ "partial_function_name_raw": "nameOf(verifyOidcClient)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/oidc/clients/verify\"",
+ "summary": "\"Verify OIDC Client\"",
+ "description": "s\"\"\"Verifies an OIDC/OAuth2 client's credentials.\n |\n |Returns `valid: true` if the client_id and client_secret match an active consumer.\n |Also returns the consumer_id and redirect_uris for use by the OIDC provider.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "VerifyOidcClientRequestJsonV600(\n client_id = \"abc123def456\",\n client_secret = \"supersecret123\"\n )",
+ "success_response_body": "VerifyOidcClientResponseJsonV600(\n valid = true,\n client_id = Some(\"abc123def456\"),\n consumer_id = Some(\"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\"),\n redirect_uris = Some(List(\"https://app.example.com/callback\"))\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagOIDC, apiTagConsumer, apiTagOAuth)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canVerifyOidcClient))"
+ }
+ },
+ "getOidcClient": {
+ "partial_function_name_raw": "nameOf(getOidcClient)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/oidc/clients/CLIENT_ID\"",
+ "summary": "\"Get OIDC Client\"",
+ "description": "s\"\"\"Gets an OIDC/OAuth2 client's metadata by client_id.\n |\n |Returns client information including name, consumer_id, redirect_uris, and enabled status.\n |This endpoint does not verify the client secret - use POST /oidc/clients/verify for authentication.\n |\n |${userAuthenticationMessage(true)}\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "GetOidcClientResponseJsonV600(\n client_id = \"abc123def456\",\n client_name = \"My Application\",\n consumer_id = \"7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh\",\n redirect_uris = List(\"https://app.example.com/callback\"),\n enabled = true\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagOIDC, apiTagConsumer, apiTagOAuth)",
+ "extra_named_args": {
+ "authMode": "UserOrApplication",
+ "roles": "Some(List(canGetOidcClient))"
+ }
+ },
+ "createFeaturedApiCollection": {
+ "partial_function_name_raw": "nameOf(createFeaturedApiCollection)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/api-collections/featured\"",
+ "summary": "\"Create Featured Api Collection\"",
+ "description": "s\"\"\"Add an API Collection to the featured list.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postFeaturedApiCollectionJsonV600",
+ "success_response_body": "featuredApiCollectionJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ApiCollectionNotFound,\n FeaturedApiCollectionAlreadyExists,\n CreateFeaturedApiCollectionError,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canManageFeaturedApiCollections))"
+ }
+ },
+ "getFeaturedApiCollectionsAdmin": {
+ "partial_function_name_raw": "nameOf(getFeaturedApiCollectionsAdmin)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/api-collections/featured\"",
+ "summary": "\"Get Featured Api Collections (Admin)\"",
+ "description": "s\"\"\"Get all featured API collections with their sort order (admin view).\n |\n |This endpoint returns the featured collections stored in the database with their sort order.\n |It is intended for administrators to manage the featured list.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "featuredApiCollectionsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canManageFeaturedApiCollections))"
+ }
+ },
+ "updateFeaturedApiCollection": {
+ "partial_function_name_raw": "nameOf(updateFeaturedApiCollection)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/management/api-collections/featured/API_COLLECTION_ID\"",
+ "summary": "\"Update Featured Api Collection\"",
+ "description": "s\"\"\"Update the sort order of a featured API collection.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "putFeaturedApiCollectionJsonV600",
+ "success_response_body": "featuredApiCollectionJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n FeaturedApiCollectionNotFound,\n UpdateFeaturedApiCollectionError,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canManageFeaturedApiCollections))"
+ }
+ },
+ "deleteFeaturedApiCollection": {
+ "partial_function_name_raw": "nameOf(deleteFeaturedApiCollection)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/management/api-collections/featured/API_COLLECTION_ID\"",
+ "summary": "\"Delete Featured Api Collection\"",
+ "description": "s\"\"\"Remove an API Collection from the featured list.\n |\n |${userAuthenticationMessage(true)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n FeaturedApiCollectionNotFound,\n DeleteFeaturedApiCollectionError,\n UnknownError\n )",
+ "tags": "List(apiTagApiCollection, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canManageFeaturedApiCollections))"
+ }
+ },
+ "getPopularApis": {
+ "partial_function_name_raw": "nameOf(getPopularApis)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api/popular-endpoints\"",
+ "summary": "\"Get Popular Endpoints\"",
+ "description": "s\"\"\"Returns the operation IDs of the 50 most popular endpoints based on usage metrics.\n |\n |This endpoint is public and does not require authentication.\n |\n |The response contains a simple list of operation_id strings, ordered by popularity (most called first).\n |\n |This includes endpoints from all API standards: OBP, Berlin Group, UK Open Banking, STET, Polish API, etc.\n |\n |Example operation_id formats:\n |* OBP: OBPv4.0.0-getBanks\n |* Berlin Group: BGv1.3-getAccountList\n |* UK Open Banking: UKv3.1-getAccounts\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "PopularApisJsonV600(\n operation_ids = List(\n \"OBPv4.0.0-getBanks\",\n \"OBPv4.0.0-getBank\",\n \"BGv1.3-getAccountList\"\n )\n )",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)"
+ },
+ "getConnectorCallCounts": {
+ "partial_function_name_raw": "nameOf(getConnectorCallCounts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/connector/metrics/counts\"",
+ "summary": "\"Get Connector Call Counts\"",
+ "description": "s\"\"\"Returns per-hour Redis counters for connector outbound and inbound messages.\n |\n |This provides real-time visibility into which connector methods are being called\n |and how many responses (success/failure) are being received.\n |\n |Counters automatically reset every hour (rolling window).\n |The ttl_seconds field shows when the current hour window resets.\n |\n |Requires the prop: write_connector_metrics_redis=true\n |\n |Redis key format:\n |\n |- Outbound (before connector call): {instance}_{env}_connector_outbound_{version}_{connectorName}_{methodName}_PER_HOUR\n |- Inbound success (after connector call): {instance}_{env}_connector_inbound_{version}_{connectorName}_{methodName}_success_PER_HOUR\n |- Inbound failure (after connector call): {instance}_{env}_connector_inbound_{version}_{connectorName}_{methodName}_failure_PER_HOUR\n |\n |For example: obp_dev_connector_outbound_1_star_getBanks_PER_HOUR\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ConnectorCountsJsonV600(\n enabled = true,\n connector_counts = List(\n ConnectorCountJsonV600(\n connector_name = \"mapped\",\n method_name = \"getBank\",\n per_hour_outbound_count = 152,\n per_hour_inbound_success_count = 150,\n per_hour_inbound_failure_count = 2,\n ttl_seconds = 2847\n )\n )\n )",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canReadMetrics))"
+ }
+ },
+ "createApiProduct": {
+ "partial_function_name_raw": "nameOf(createApiProduct)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE\"",
+ "summary": "\"Create Api Product\"",
+ "description": "s\"\"\"Create an Api Product for the Bank.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postPutApiProductJsonV600",
+ "success_response_body": "apiProductJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n CreateApiProductError,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateApiProduct))"
+ }
+ },
+ "createOrUpdateApiProduct": {
+ "partial_function_name_raw": "nameOf(createOrUpdateApiProduct)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE\"",
+ "summary": "\"Create or Update Api Product\"",
+ "description": "s\"\"\"Create or Update an Api Product for the Bank.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postPutApiProductJsonV600",
+ "success_response_body": "apiProductJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n CreateApiProductError,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateApiProduct))"
+ }
+ },
+ "getApiProduct": {
+ "partial_function_name_raw": "nameOf(getApiProduct)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE\"",
+ "summary": "\"Get Api Product\"",
+ "description": "s\"\"\"Get an Api Product by BANK_ID and API_PRODUCT_CODE.\n |\n |Returns the Api Product with its attributes.\n |\n |${userAuthenticationMessage(!getApiProductsIsPublic)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiProductJsonV600",
+ "error_response_bodies": "if (getApiProductsIsPublic) List(ApiProductNotFound, UnknownError) else List(UserHasMissingRoles, ApiProductNotFound, UnknownError)",
+ "tags": "List(apiTagApi, apiTagApiProduct)",
+ "extra_named_args": {
+ "roles": "if (getApiProductsIsPublic) None else Some(List(canGetApiProduct))"
+ }
+ },
+ "getApiProducts": {
+ "partial_function_name_raw": "nameOf(getApiProducts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/api-products\"",
+ "summary": "\"Get Api Products\"",
+ "description": "s\"\"\"Get Api Products for the Bank.\n |\n |Optional query parameter: `tag` — filter to products that have the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive.\n |\n |${userAuthenticationMessage(!getApiProductsIsPublic)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiProductsJsonV600",
+ "error_response_bodies": "if (getApiProductsIsPublic) List(UnknownError) else List(UserHasMissingRoles, UnknownError)",
+ "tags": "List(apiTagApi, apiTagApiProduct)",
+ "extra_named_args": {
+ "roles": "if (getApiProductsIsPublic) None else Some(List(canGetApiProduct))"
+ }
+ },
+ "getAllApiProductsV600": {
+ "partial_function_name_raw": "nameOf(getAllApiProductsV600)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/api-products\"",
+ "summary": "\"Get Api Products At All Banks\"",
+ "description": "s\"\"\"Returns the Api Products across every bank, merged into a single list. Each product carries its `bank_id`.\n |\n |Optional query parameter `tag` — filter to products that have the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive.\n |\n |${userAuthenticationMessage(!getApiProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiProductsJsonV600",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagApi, apiTagApiProduct)"
+ },
+ "deleteApiProduct": {
+ "partial_function_name_raw": "nameOf(deleteApiProduct)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE\"",
+ "summary": "\"Delete Api Product\"",
+ "description": "s\"\"\"Delete an Api Product by BANK_ID and API_PRODUCT_CODE.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ApiProductNotFound,\n DeleteApiProductError,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProduct)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteApiProduct))"
+ }
+ },
+ "getProductsV600": {
+ "partial_function_name_raw": "nameOf(getProductsV600)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products\"",
+ "summary": "\"Get Products\"",
+ "description": "s\"\"\"Returns the financial Products offered by the bank specified by BANK_ID. Response includes the new `tags` field.\n |\n |Optional query parameter `tag` — filter to products that carry the given tag (case-insensitive). Repeat `tag=` to require multiple tags (e.g. `?tag=featured&tag=new`).\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJsonV600",
+ "error_response_bodies": "List(\n BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "getAllProductsV600": {
+ "partial_function_name_raw": "nameOf(getAllProductsV600)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/products\"",
+ "summary": "\"Get Products At All Banks\"",
+ "description": "s\"\"\"Returns the financial Products offered by every bank this instance knows about, merged into a single list. Each product carries its `bank_id`.\n |\n |Optional query parameter `tag` — filter to products that carry the given tag (e.g. `?tag=featured`). Tag matching is case-insensitive. Repeat `tag=` to require multiple tags.\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productsJsonV600",
+ "error_response_bodies": "List(UnknownError)",
+ "tags": "List(apiTagProduct)"
+ },
+ "getProductTagsV600": {
+ "partial_function_name_raw": "nameOf(getProductTagsV600)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/tags\"",
+ "summary": "\"Get Product Tags\"",
+ "description": "s\"\"\"Returns the list of tags currently set on the financial Product.\n |\n |${userAuthenticationMessage(!getProductsIsPublic)}\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "productTagsJsonV600",
+ "error_response_bodies": "List(\n BankNotFound,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)"
+ },
+ "updateProductTagsV600": {
+ "partial_function_name_raw": "nameOf(updateProductTagsV600)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/products/PRODUCT_CODE/tags\"",
+ "summary": "\"Update Product Tags\"",
+ "description": "s\"\"\"Replaces the tags on a financial Product. Tags are free-form string labels (e.g. `featured`, `new`, `beta`). Tag matching in queries is case-insensitive.\n |\n |Authentication is Required.\"\"\".stripMargin",
+ "example_request_body": "productTagsJsonV600",
+ "success_response_body": "productTagsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n BankNotFound,\n ProductNotFoundByProductCode,\n UnknownError\n )",
+ "tags": "List(apiTagProduct)",
+ "extra_named_args": {
+ "roles": "Some(updateProductTagsEntitlements)"
+ }
+ },
+ "createApiProductAttribute": {
+ "partial_function_name_raw": "nameOf(createApiProductAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE/attribute\"",
+ "summary": "\"Create Api Product Attribute\"",
+ "description": "s\"\"\"Create an Api Product Attribute.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "apiProductAttributeJsonV600",
+ "success_response_body": "apiProductAttributeResponseJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n ApiProductNotFound,\n CreateApiProductAttributeError,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProductAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateApiProductAttribute))"
+ }
+ },
+ "updateApiProductAttribute": {
+ "partial_function_name_raw": "nameOf(updateApiProductAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Update Api Product Attribute\"",
+ "description": "s\"\"\"Update an Api Product Attribute.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "apiProductAttributeJsonV600",
+ "success_response_body": "apiProductAttributeResponseJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n ApiProductNotFound,\n ApiProductAttributeNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProductAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateApiProductAttribute))"
+ }
+ },
+ "getApiProductAttribute": {
+ "partial_function_name_raw": "nameOf(getApiProductAttribute)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Get Api Product Attribute\"",
+ "description": "s\"\"\"Get an Api Product Attribute by API_PRODUCT_ATTRIBUTE_ID.\n |\n |${userAuthenticationMessage(!getApiProductsIsPublic)}\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "apiProductAttributeResponseJsonV600",
+ "error_response_bodies": "if (getApiProductsIsPublic) List(ApiProductAttributeNotFound, UnknownError) else List(UserHasMissingRoles, ApiProductAttributeNotFound, UnknownError)",
+ "tags": "List(apiTagApi, apiTagApiProductAttribute)",
+ "extra_named_args": {
+ "roles": "if (getApiProductsIsPublic) None else Some(List(canGetApiProductAttribute))"
+ }
+ },
+ "deleteApiProductAttribute": {
+ "partial_function_name_raw": "nameOf(deleteApiProductAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/api-products/API_PRODUCT_CODE/attributes/API_PRODUCT_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Api Product Attribute\"",
+ "description": "s\"\"\"Delete an Api Product Attribute by API_PRODUCT_ATTRIBUTE_ID.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ApiProductAttributeNotFound,\n DeleteApiProductAttributeError,\n UnknownError\n )",
+ "tags": "List(apiTagApi, apiTagApiProductAttribute)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteApiProductAttribute))"
+ }
+ },
+ "getConnectorTraces": {
+ "partial_function_name_raw": "nameOf(getConnectorTraces)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/connector/traces\"",
+ "summary": "\"Get Connector Traces\"",
+ "description": "s\"\"\"Get connector traces which capture the full outbound/inbound messages for each connector call.\n |\n |Connector tracing must be enabled via the write_connector_trace=true property.\n |\n |Filters Part 1.*filtering* parameters to GET /management/connector/traces\n |\n |Should be able to filter on the following fields:\n |\n |eg: /management/connector/traces?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2\n |\n |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString\n |\n |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString\n |\n |3 limit (for pagination: defaults to 1000) eg:limit=2000\n |\n |4 offset (for pagination: zero index, defaults to 0) eg: offset=10\n |\n |5 connector_name (if null ignore)\n |\n |6 function_name (if null ignore)\n |\n |7 correlation_id (if null ignore)\n |\n |8 bank_id (if null ignore)\n |\n |9 user_id (if null ignore)\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "connectorTracesJsonV600",
+ "error_response_bodies": "List(\n InvalidDateFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMetric, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConnectorTrace))"
+ }
+ },
+ "getConfigProps": {
+ "partial_function_name_raw": "nameOf(getConfigProps)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/management/config-props\"",
+ "summary": "\"Get Config Props\"",
+ "description": "s\"\"\"Get the active configuration properties and their runtime values.\n |\n |This endpoint uses a self-registration mechanism: each time the code calls\n |getPropsValue, getPropsAsBoolValue, getPropsAsIntValue, or getPropsAsLongValue\n |with a default value, that property key is registered.\n |\n |Only registered properties are returned. The list grows as more code paths are\n |exercised. Most properties are registered at startup.\n |\n |For each property, the value shown is the actual runtime value. If the property\n |is not explicitly set, the code-defined default is shown.\n |\n |The response includes both regular and webui_ properties, sorted alphabetically by key.\n |\n |Properties with sensitive keys or values (containing ${APIUtil.sensitiveKeywords.mkString(\", \")})\n |are excluded from the response entirely.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "configPropsJsonV600",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetConfigProps))"
+ }
+ },
+ "getAppDirectory": {
+ "partial_function_name_raw": "nameOf(getAppDirectory)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/app-directory\"",
+ "summary": "\"Get App Directory\"",
+ "description": "s\"\"\"Get connectivity information for apps in the OBP ecosystem.\n |\n |Returns configuration properties that apps (Portal, API Explorer, API Manager,\n |Sandbox Populator, OIDC, Keycloak, Hola, MCP, Opey) and agents can use to discover\n |endpoints in the OBP ecosystem.\n |\n |Any props starting with public_ and ending with _url are included automatically.\n |\n |Known public app URL props:\n |${APIUtil.publicAppUrlPropNames.mkString(\", \")}\n |\n |Empty (unconfigured) values are excluded from the response.\n |\n |Authentication is NOT Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "appDirectoryJsonV600",
+ "error_response_bodies": "List(\n UnknownError\n )",
+ "tags": "List(apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List())"
+ }
+ },
+ "backupSystemDynamicEntity": {
+ "partial_function_name_raw": "nameOf(backupSystemDynamicEntity)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/system-dynamic-entities/DYNAMIC_ENTITY_ID/backup\"",
+ "summary": "\"Backup System Level Dynamic Entity\"",
+ "description": "s\"\"\"Create a backup copy of a system level DynamicEntity specified by DYNAMIC_ENTITY_ID.\n |\n |This endpoint creates a backup of the dynamic entity definition and all its data records.\n |The backup entity will be named with a _BAK suffix (e.g. my_entity_BAK).\n |If a backup with that name already exists, _BAK2, _BAK3 etc. will be used.\n |\n |The calling user will be granted CanGetDynamicEntity_`` on the newly created backup entity.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"my_entity_BAK\",\n user_id = \"user-456\",\n bank_id = None,\n has_personal_entity = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"Backup entity\", \"required\": [\"name\"], \"properties\": {\"name\": {\"type\": \"string\", \"example\": \"test\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canBackupSystemDynamicEntity))"
+ }
+ },
+ "backupBankLevelDynamicEntity": {
+ "partial_function_name_raw": "nameOf(backupBankLevelDynamicEntity)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID/backup\"",
+ "summary": "\"Backup Bank Level Dynamic Entity\"",
+ "description": "s\"\"\"Create a backup copy of a bank level DynamicEntity specified by DYNAMIC_ENTITY_ID.\n |\n |This endpoint creates a backup of the dynamic entity definition and all its data records.\n |The backup entity will be named with a _BAK suffix (e.g. my_entity_BAK).\n |If a backup with that name already exists, _BAK2, _BAK3 etc. will be used.\n |\n |The calling user will be granted CanGetDynamicEntity_`` on the newly created backup entity.\n |\n |For more information see ${Glossary.getGlossaryItemLink(\"Dynamic-Entities\")}\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "DynamicEntityDefinitionJsonV600(\n dynamic_entity_id = \"abc-123-def\",\n entity_name = \"my_entity_BAK\",\n user_id = \"user-456\",\n bank_id = Some(\"gh.29.uk\"),\n has_personal_entity = false,\n schema = com.openbankproject.commons.util.JsonAliases.parse(\"\"\"{\"description\": \"Backup entity\", \"required\": [\"name\"], \"properties\": {\"name\": {\"type\": \"string\", \"example\": \"test\"}}}\"\"\").asInstanceOf[org.json4s.JsonAST.JObject]\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagManageDynamicEntity, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canBackupBankLevelDynamicEntity))"
+ }
+ },
+ "createAccountAccessRequest": {
+ "partial_function_name_raw": "nameOf(createAccountAccessRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests\"",
+ "summary": "\"Create Account Access Request\"",
+ "description": "s\"\"\"Create a new Account Access Request (maker step in maker/checker workflow).\n |\n |The requestor (maker) creates a request to grant a target user access to a specific view on an account.\n |A business justification is required.\n |\n |The request is created with status INITIATED and must be approved or rejected by a different user (checker).\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "JSONFactory600.PostAccountAccessRequestJsonV600(\n target_user_id = ExampleValue.userIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n business_justification = \"Need access to review monthly account statements for audit purposes.\"\n )",
+ "success_response_body": "JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"INITIATED\",\n checker_user_id = \"\",\n checker_comment = \"\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n $BankNotFound,\n $BankAccountNotFound,\n BusinessJustificationRequired,\n AccountAccessRequestAlreadyExists,\n AccountAccessRequestCannotBeCreated,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateAccountAccessRequestAtOneBank, canCreateAccountAccessRequestAtAnyBank))"
+ }
+ },
+ "getAccountAccessRequestsForAccount": {
+ "partial_function_name_raw": "nameOf(getAccountAccessRequestsForAccount)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests\"",
+ "summary": "\"Get Account Access Requests for Account\"",
+ "description": "s\"\"\"Get Account Access Requests for a specific account (checker view).\n |\n |Optionally filter by status using the query parameter: ?status=INITIATED\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.AccountAccessRequestsJsonV600(\n account_access_requests = List(JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"INITIATED\",\n checker_user_id = \"\",\n checker_comment = \"\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n ))\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n $BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountAccessRequestsAtOneBank, canGetAccountAccessRequestsAtAnyBank))"
+ }
+ },
+ "getMyAccountAccessRequests": {
+ "partial_function_name_raw": "nameOf(getMyAccountAccessRequests)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/my/account-access-requests\"",
+ "summary": "\"Get My Account Access Requests\"",
+ "description": "s\"\"\"Get Account Access Requests created by the current user (maker view).\n |\n |No special roles are required — a user can always see their own requests.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.AccountAccessRequestsJsonV600(\n account_access_requests = List(JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"INITIATED\",\n checker_user_id = \"\",\n checker_comment = \"\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n ))\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getAccountAccessRequestById": {
+ "partial_function_name_raw": "nameOf(getAccountAccessRequestById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID\"",
+ "summary": "\"Get Account Access Request by Id\"",
+ "description": "s\"\"\"Get a single Account Access Request by its ID.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"INITIATED\",\n checker_user_id = \"\",\n checker_comment = \"\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n $BankAccountNotFound,\n AccountAccessRequestNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountAccessRequestsAtOneBank, canGetAccountAccessRequestsAtAnyBank))"
+ }
+ },
+ "approveAccountAccessRequest": {
+ "partial_function_name_raw": "nameOf(approveAccountAccessRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID/approval\"",
+ "summary": "\"Approve Account Access Request\"",
+ "description": "s\"\"\"Approve an Account Access Request (checker step in maker/checker workflow).\n |\n |The checker must be a different user than the maker (requestor). This enforces dual control / maker-checker separation.\n |\n |Only requests with status INITIATED can be approved.\n |\n |On approval, the system automatically grants the target user access to the specified view.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "JSONFactory600.PostApproveAccountAccessRequestJsonV600(\n comment = Some(\"Approved for Q1 audit.\")\n )",
+ "success_response_body": "JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"APPROVED\",\n checker_user_id = \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n checker_comment = \"Approved for Q1 audit.\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n $BankNotFound,\n $BankAccountNotFound,\n AccountAccessRequestNotFound,\n AccountAccessRequestStatusNotInitiated,\n MakerCheckerSameUser,\n AccountAccessRequestCannotBeUpdated,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAccountAccessRequestAtOneBank, canUpdateAccountAccessRequestAtAnyBank))"
+ }
+ },
+ "rejectAccountAccessRequest": {
+ "partial_function_name_raw": "nameOf(rejectAccountAccessRequest)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/account-access-requests/ACCOUNT_ACCESS_REQUEST_ID/rejection\"",
+ "summary": "\"Reject Account Access Request\"",
+ "description": "s\"\"\"Reject an Account Access Request (checker step in maker/checker workflow).\n |\n |The checker must be a different user than the maker (requestor). This enforces dual control / maker-checker separation.\n |\n |Only requests with status INITIATED can be rejected.\n |\n |A comment is required when rejecting a request.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "JSONFactory600.PostRejectAccountAccessRequestJsonV600(\n comment = \"Insufficient business justification provided.\"\n )",
+ "success_response_body": "JSONFactory600.AccountAccessRequestJsonV600(\n account_access_request_id = \"b4e0352a-9a0f-4bfa-b30b-9003aa467f51\",\n bank_id = ExampleValue.bankIdExample.value,\n account_id = ExampleValue.accountIdExample.value,\n view_id = ExampleValue.viewIdExample.value,\n is_system_view = true,\n requestor_user_id = ExampleValue.userIdExample.value,\n target_user_id = \"9ca9a7e4-6d02-40e3-a129-0b2bf89de9b2\",\n business_justification = \"Need access to review monthly account statements for audit purposes.\",\n status = \"REJECTED\",\n checker_user_id = \"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0\",\n checker_comment = \"Insufficient business justification provided.\",\n created = APIUtil.DateWithMsExampleObject,\n updated = APIUtil.DateWithMsExampleObject\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n InvalidJsonFormat,\n $BankNotFound,\n $BankAccountNotFound,\n AccountAccessRequestNotFound,\n AccountAccessRequestStatusNotInitiated,\n MakerCheckerSameUser,\n CheckerCommentRequiredForRejection,\n AccountAccessRequestCannotBeUpdated,\n UnknownError\n )",
+ "tags": "List(apiTagAccountAccessRequest)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateAccountAccessRequestAtOneBank, canUpdateAccountAccessRequestAtAnyBank))"
+ }
+ },
+ "publishSignalMessage": {
+ "partial_function_name_raw": "nameOf(publishSignalMessage)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/signal/channels/CHANNEL_NAME/messages\"",
+ "summary": "\"Publish Signal Message\"",
+ "description": "s\"\"\"Publish a message to a signal channel.\n |\n |Signal channels provide short-lived, Redis-backed messaging for lightweight coordination between\n |AI agents and other OBP consumers. Messages are not persisted to a database.\n |\n |Channels are auto-created on first publish and expire after a configurable TTL (default 1 hour).\n |Messages are capped at a configurable maximum per channel (default 1000).\n |\n |The payload field accepts any valid JSON content.\n |\n |Set to_user_id to send a private message visible only to the sender and recipient.\n |Leave to_user_id empty for a broadcast message visible to all channel readers.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "postSignalMessageJsonV600",
+ "success_response_body": "signalMessagePublishedJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n InvalidSignalChannelName,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)"
+ },
+ "getSignalMessages": {
+ "partial_function_name_raw": "nameOf(getSignalMessages)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/signal/channels/CHANNEL_NAME/messages\"",
+ "summary": "\"Get Signal Messages\"",
+ "description": "s\"\"\"Fetch messages from a signal channel with offset/limit pagination.\n |\n |Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery\n |and coordination, but usable by any authenticated OBP consumer.\n |\n |Messages are returned oldest-first.\n |\n |Privacy filtering is applied server-side: you will only see broadcast messages (no to_user_id)\n |and private messages addressed to you (to_user_id matches your user ID) or sent by you.\n |\n |Use the offset parameter to poll for new messages by tracking your position.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "signalMessagesJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidSignalChannelName,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)"
+ },
+ "getSignalChannels": {
+ "partial_function_name_raw": "nameOf(getSignalChannels)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/signal/channels\"",
+ "summary": "\"List Signal Channels\"",
+ "description": "s\"\"\"Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.\n |Messages are ephemeral and will expire after the configured TTL (default 1 hour).\n |\n |This endpoint lists active signal channels.\n |Only channels that contain at least one broadcast message (no to_user_id) are listed.\n |Private-only channels are not shown.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "signalChannelsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)"
+ },
+ "getSignalChannelInfo": {
+ "partial_function_name_raw": "nameOf(getSignalChannelInfo)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/signal/channels/CHANNEL_NAME/info\"",
+ "summary": "\"Get Signal Channel Info\"",
+ "description": "s\"\"\"Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.\n |Messages are ephemeral and will expire after the configured TTL (default 1 hour).\n |\n |This endpoint returns metadata about a signal channel including the current message count and remaining TTL in seconds.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "signalChannelInfoJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidSignalChannelName,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)"
+ },
+ "deleteSignalChannel": {
+ "partial_function_name_raw": "nameOf(deleteSignalChannel)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/signal/channels/CHANNEL_NAME\"",
+ "summary": "\"Delete Signal Channel\"",
+ "description": "s\"\"\"Signal channels provide short-lived, Redis-backed messaging designed for AI agent discovery and coordination, but usable by any authenticated OBP consumer.\n |Messages are ephemeral and will expire after the configured TTL (default 1 hour).\n |\n |This endpoint deletes a signal channel and all its messages immediately.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "signalChannelDeletedJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidSignalChannelName,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)"
+ },
+ "getSignalStats": {
+ "partial_function_name_raw": "nameOf(getSignalStats)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/signal/channels/stats\"",
+ "summary": "\"Get Signal Channel Stats\"",
+ "description": "s\"\"\"Returns statistics for all signal channels, including private-only channels.\n |\n |Unlike the List Signal Channels endpoint, this does not filter out private-only channels.\n |It provides a complete view of all active channels with message counts and TTL info.\n |\n |Authentication is Required.\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "signalStatsJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagAiAgent, apiTagSignal, apiTagSignalling, apiTagChannel)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSignalStats))"
+ }
+ },
+ "getAccountDirectory": {
+ "partial_function_name_raw": "nameOf(getAccountDirectory)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/account-directory\"",
+ "summary": "\"Get Account Directory at Bank\"",
+ "description": "s\"\"\"Returns a list of accounts at the bank with identifiers and metadata.\n |\n |This endpoint is designed for management UIs that need to list accounts\n |without exposing sensitive data (balance and owners are excluded).\n |\n |The response includes: account_id, bank_id, label, account_number, account_type, branch_id,\n |account_routings, account_attributes and view_ids.\n |\n |${urlParametersDocument(true, false)}\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.AccountDirectoryJsonV600(\n accounts = List(JSONFactory600.AccountDirectoryItemJsonV600(\n account_id = ExampleValue.accountIdExample.value,\n bank_id = ExampleValue.bankIdExample.value,\n label = \"My Account\",\n account_number = \"123456789\",\n account_type = \"CURRENT\",\n branch_id = \"BRANCH_1\",\n account_routings = List(FastFirehoseRoutings(bank_id = ExampleValue.bankIdExample.value, account_id = ExampleValue.accountIdExample.value)),\n account_attributes = List(FastFirehoseAttributes(`type` = \"STRING\", code = \"OVERDRAFT_LIMIT\", value = \"1000\")),\n view_ids = List(\"owner\")\n ))\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetAccountDirectoryAtOneBank))"
+ }
+ },
+ "hasAccountAccess": {
+ "partial_function_name_raw": "nameOf(hasAccountAccess)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/has-account-access\"",
+ "summary": "\"Has Account Access\"",
+ "description": "s\"\"\"Check whether the authenticated user has access to a specific view on a specific account.\n |\n |Returns a boolean `has_account_access` along with the `access_source` (currently \"ACCOUNT_ACCESS\")\n |and the `account_access_id` (primary key of the AccountAccess record).\n |\n |If the user does not have access, `has_account_access` is false and the other fields are empty strings.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JSONFactory600.HasAccountAccessJsonV600(\n has_account_access = true,\n access_source = \"ACCOUNT_ACCESS\",\n account_access_id = ExampleValue.uuidExample.value,\n abac_rule_id = \"\"\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagView, apiTagAccount)"
+ },
+ "getUsersWithAccountAccess": {
+ "partial_function_name_raw": "nameOf(getUsersWithAccountAccess)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/users-with-access\"",
+ "summary": "\"Get Users With Account Access\"",
+ "description": "s\"\"\"Get all users who have access to a specific view on a specific account, and how that access was granted.\n |\n |This endpoint combines both traditional AccountAccess records and ABAC (Attribute-Based Access Control)\n |evaluation to provide a complete picture of who can access the specified view.\n |\n |Each user entry includes an access_source indicating how access was granted\n |(either \"ACCOUNT_ACCESS\" for direct grants or \"ABAC\" for rule-based access).\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "UsersWithViewAccessJsonV600(\n users = List(UserWithViewAccessJsonV600(\n user_id = ExampleValue.userIdExample.value,\n username = \"robert.x.smith.test\",\n email = \"robert.x@example.com\",\n provider = \"https://apisandbox.openbankproject.com\",\n access_source = \"ACCOUNT_ACCESS\"\n ))\n )",
+ "error_response_bodies": "List(\n $BankNotFound,\n BankAccountNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagAccount, apiTagView)",
+ "extra_named_args": {
+ "roles": "Some(List(canSeeAccountAccessForAnyUser))"
+ }
+ },
+ "getPrivateAccountByIdFull": {
+ "partial_function_name_raw": "nameOf(getPrivateAccountByIdFull)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account\"",
+ "summary": "\"Get Account by Id (Full)\"",
+ "description": "\"\"\"Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID):\n |\n |* Number\n |* Owners\n |* Type\n |* Balance\n |* Available views (sorted by view_name)\n |\n |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount).\n |\n |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications.\n |This call provides balance and other account information via delegated authentication using OAuth.\n |\n |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`.\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ModeratedAccountJSON600(\n id = \"5995d6a2-01b3-423c-a173-5481df49bdaf\",\n label = \"NoneLabel\",\n number = \"123\",\n owners = List(userJSONV121),\n product_code = ExampleValue.productCodeExample.value,\n balance = amountOfMoneyJsonV121,\n views_available = List(ViewJsonV600(\n bank_id = \"\",\n account_id = \"\",\n view_id = \"owner\",\n view_name = \"Owner\",\n description = \"The owner of the account\",\n metadata_view = \"owner\",\n is_public = false,\n is_system = true,\n is_firehose = Some(false),\n alias = \"private\",\n hide_metadata_if_alias_used = false,\n can_grant_access_to_views = List(\"owner\"),\n can_revoke_access_to_views = List(\"owner\"),\n allowed_actions = List(\"can_see_transaction_amount\", \"can_see_bank_account_balance\")\n )),\n bank_id = ExampleValue.bankIdExample.value,\n account_routings = List(accountRoutingJsonV121),\n account_attributes = List(accountAttributeResponseJson),\n tags = List(accountTagJSON)\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n $BankAccountNotFound,\n $UserNoPermissionAccessView,\n UnknownError\n )",
+ "tags": "apiTagAccount :: Nil"
+ },
+ "createMandate": {
+ "partial_function_name_raw": "nameOf(createMandate)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/mandates\"",
+ "summary": "\"Create Mandate\"",
+ "description": "s\"\"\"Create a new mandate for a bank account.\n |\n |A mandate is a legal document that defines who can operate an account, what they can do,\n |and under what conditions (e.g., signatory requirements, amount thresholds).\n |\n |Mandates tie together OBP constructs such as Views, ABAC Rules, Signatory Panels,\n |and Challenges into a coherent authorization policy.\n |\n |**Status values:** ACTIVE, SUSPENDED, EXPIRED, DRAFT\n |\n |**Date format:** yyyy-MM-dd'T'HH:mm:ss'Z' (UTC)\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "CreateMandateJsonV600(\n customer_id = \"customer-id-123\",\n mandate_name = \"ACME Corp Operating Account Authority\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"The following persons are authorised to operate this account...\",\n description = \"Payment and account access authority for ACME Corp\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\"\n )",
+ "success_response_body": "MandateJsonV600(\n mandate_id = \"mandate-id-123\",\n bank_id = \"gh.29.uk\",\n account_id = \"8ca8a7e4-6d02\",\n customer_id = \"customer-id-123\",\n mandate_name = \"ACME Corp Operating Account Authority\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"The following persons are authorised to operate this account...\",\n description = \"Payment and account access authority for ACME Corp\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\",\n created_by_user_id = \"user-id-123\",\n updated_by_user_id = \"user-id-123\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateMandate))"
+ }
+ },
+ "getMandates": {
+ "partial_function_name_raw": "nameOf(getMandates)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/mandates\"",
+ "summary": "\"Get Mandates for Account\"",
+ "description": "s\"\"\"Get all mandates for a bank account.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MandatesJsonV600(List(MandateJsonV600(\n mandate_id = \"mandate-id-123\",\n bank_id = \"gh.29.uk\",\n account_id = \"8ca8a7e4-6d02\",\n customer_id = \"customer-id-123\",\n mandate_name = \"ACME Corp Operating Account Authority\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"The following persons are authorised...\",\n description = \"Payment authority for ACME Corp\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\",\n created_by_user_id = \"user-id-123\",\n updated_by_user_id = \"user-id-123\"\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMandate))"
+ }
+ },
+ "getMandate": {
+ "partial_function_name_raw": "nameOf(getMandate)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID\"",
+ "summary": "\"Get Mandate\"",
+ "description": "s\"\"\"Get a mandate by its ID.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MandateJsonV600(\n mandate_id = \"mandate-id-123\",\n bank_id = \"gh.29.uk\",\n account_id = \"8ca8a7e4-6d02\",\n customer_id = \"customer-id-123\",\n mandate_name = \"ACME Corp Operating Account Authority\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"The following persons are authorised...\",\n description = \"Payment authority for ACME Corp\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\",\n created_by_user_id = \"user-id-123\",\n updated_by_user_id = \"user-id-123\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMandate))"
+ }
+ },
+ "updateMandate": {
+ "partial_function_name_raw": "nameOf(updateMandate)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID\"",
+ "summary": "\"Update Mandate\"",
+ "description": "s\"\"\"Update a mandate.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "UpdateMandateJsonV600(\n mandate_name = \"Updated Mandate Name\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"Updated legal text...\",\n description = \"Updated description\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\"\n )",
+ "success_response_body": "MandateJsonV600(\n mandate_id = \"mandate-id-123\",\n bank_id = \"gh.29.uk\",\n account_id = \"8ca8a7e4-6d02\",\n customer_id = \"customer-id-123\",\n mandate_name = \"Updated Mandate Name\",\n mandate_reference = \"MND-2026-00042\",\n legal_text = \"Updated legal text...\",\n description = \"Updated description\",\n status = \"ACTIVE\",\n valid_from = \"2026-01-01T00:00:00Z\",\n valid_to = \"2027-01-01T00:00:00Z\",\n created_by_user_id = \"user-id-123\",\n updated_by_user_id = \"user-id-456\"\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateMandate))"
+ }
+ },
+ "deleteMandate": {
+ "partial_function_name_raw": "nameOf(deleteMandate)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/mandates/MANDATE_ID\"",
+ "summary": "\"Delete Mandate\"",
+ "description": "s\"\"\"Delete a mandate and all its provisions and signatory panels.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteMandate))"
+ }
+ },
+ "createMandateProvision": {
+ "partial_function_name_raw": "nameOf(createMandateProvision)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/provisions\"",
+ "summary": "\"Create Mandate Provision\"",
+ "description": "s\"\"\"Create a new provision for a mandate.\n |\n |A provision links the mandate's legal clauses to OBP enforcement mechanisms\n |(Views, ABAC Rules, Challenges).\n |\n |**Provision types:**\n |- SIGNATORY_RULE — Who can sign and in what combination\n |- VIEW_ASSIGNMENT — Which view a signatory panel gets on the account\n |- ABAC_CONDITION — Links to an ABAC rule for attribute-based conditions\n |- RESTRICTION — Negative rule (e.g., no international payments)\n |- NOTIFICATION — Triggers notification rather than blocking\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "CreateMandateProvisionJsonV600(\n provision_name = \"Payments under 5000\",\n provision_description = \"Any single Director may authorise payments below EUR 5,000\",\n legal_reference = \"Clause 3.1(a)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 5000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 1)),\n linked_view_id = Some(\"PaymentInitiator\"),\n linked_abac_rule_id = None,\n linked_challenge_type = Some(\"OBP_TRANSACTION_REQUEST_CHALLENGE\"),\n is_active = true,\n sort_order = 1\n )",
+ "success_response_body": "MandateProvisionJsonV600(\n provision_id = \"provision-id-123\",\n mandate_id = \"mandate-id-123\",\n provision_name = \"Payments under 5000\",\n provision_description = \"Any single Director may authorise payments below EUR 5,000\",\n legal_reference = \"Clause 3.1(a)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 5000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 1)),\n linked_view_id = \"PaymentInitiator\",\n linked_abac_rule_id = \"\",\n linked_challenge_type = \"OBP_TRANSACTION_REQUEST_CHALLENGE\",\n is_active = true,\n sort_order = 1\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateMandateProvision))"
+ }
+ },
+ "getMandateProvisions": {
+ "partial_function_name_raw": "nameOf(getMandateProvisions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/provisions\"",
+ "summary": "\"Get Mandate Provisions\"",
+ "description": "s\"\"\"Get all provisions for a mandate.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MandateProvisionsJsonV600(List(MandateProvisionJsonV600(\n provision_id = \"provision-id-123\",\n mandate_id = \"mandate-id-123\",\n provision_name = \"Payments under 5000\",\n provision_description = \"Any single Director may authorise payments below EUR 5,000\",\n legal_reference = \"Clause 3.1(a)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 5000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 1)),\n linked_view_id = \"PaymentInitiator\",\n linked_abac_rule_id = \"\",\n linked_challenge_type = \"OBP_TRANSACTION_REQUEST_CHALLENGE\",\n is_active = true,\n sort_order = 1\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMandateProvision))"
+ }
+ },
+ "getMandateProvision": {
+ "partial_function_name_raw": "nameOf(getMandateProvision)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID\"",
+ "summary": "\"Get Mandate Provision\"",
+ "description": "s\"\"\"Get a specific provision by its ID.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "MandateProvisionJsonV600(\n provision_id = \"provision-id-123\",\n mandate_id = \"mandate-id-123\",\n provision_name = \"Payments under 5000\",\n provision_description = \"Any single Director may authorise payments below EUR 5,000\",\n legal_reference = \"Clause 3.1(a)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 5000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 1)),\n linked_view_id = \"PaymentInitiator\",\n linked_abac_rule_id = \"\",\n linked_challenge_type = \"OBP_TRANSACTION_REQUEST_CHALLENGE\",\n is_active = true,\n sort_order = 1\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetMandateProvision))"
+ }
+ },
+ "updateMandateProvision": {
+ "partial_function_name_raw": "nameOf(updateMandateProvision)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID\"",
+ "summary": "\"Update Mandate Provision\"",
+ "description": "s\"\"\"Update a mandate provision.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "UpdateMandateProvisionJsonV600(\n provision_name = \"Updated provision\",\n provision_description = \"Updated description\",\n legal_reference = \"Clause 3.1(b)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 50000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 2)),\n linked_view_id = Some(\"PaymentInitiator\"),\n linked_abac_rule_id = None,\n linked_challenge_type = Some(\"OBP_TRANSACTION_REQUEST_CHALLENGE\"),\n is_active = true,\n sort_order = 2\n )",
+ "success_response_body": "MandateProvisionJsonV600(\n provision_id = \"provision-id-123\",\n mandate_id = \"mandate-id-123\",\n provision_name = \"Updated provision\",\n provision_description = \"Updated description\",\n legal_reference = \"Clause 3.1(b)\",\n provision_type = \"SIGNATORY_RULE\",\n conditions = \"\"\"{\"currency\": \"EUR\", \"amount_below\": 50000.00}\"\"\",\n signatory_requirements = List(SignatoryRequirementJsonV600(panel_id = \"panel-id-001\", required_count = 2)),\n linked_view_id = \"PaymentInitiator\",\n linked_abac_rule_id = \"\",\n linked_challenge_type = \"OBP_TRANSACTION_REQUEST_CHALLENGE\",\n is_active = true,\n sort_order = 2\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateMandateProvision))"
+ }
+ },
+ "deleteMandateProvision": {
+ "partial_function_name_raw": "nameOf(deleteMandateProvision)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/provisions/PROVISION_ID\"",
+ "summary": "\"Delete Mandate Provision\"",
+ "description": "s\"\"\"Delete a mandate provision.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteMandateProvision))"
+ }
+ },
+ "createSignatoryPanel": {
+ "partial_function_name_raw": "nameOf(createSignatoryPanel)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels\"",
+ "summary": "\"Create Signatory Panel\"",
+ "description": "s\"\"\"Create a new signatory panel for a mandate.\n |\n |A signatory panel is a named set of authorised signatories (users) that can be\n |referenced by mandate provisions. For example, \"Panel A - Directors\" and \"Panel B - Finance\".\n |\n |Provision rules then reference panels, e.g., \"1 from Panel A and 1 from Panel B\".\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "CreateSignatoryPanelJsonV600(\n panel_name = \"Panel A - Directors\",\n description = \"Board directors authorised to sign\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-3\")\n )",
+ "success_response_body": "SignatoryPanelJsonV600(\n panel_id = \"panel-id-001\",\n mandate_id = \"mandate-id-123\",\n panel_name = \"Panel A - Directors\",\n description = \"Board directors authorised to sign\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-3\")\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateSignatoryPanel))"
+ }
+ },
+ "getSignatoryPanels": {
+ "partial_function_name_raw": "nameOf(getSignatoryPanels)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels\"",
+ "summary": "\"Get Signatory Panels\"",
+ "description": "s\"\"\"Get all signatory panels for a mandate.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "SignatoryPanelsJsonV600(List(SignatoryPanelJsonV600(\n panel_id = \"panel-id-001\",\n mandate_id = \"mandate-id-123\",\n panel_name = \"Panel A - Directors\",\n description = \"Board directors authorised to sign\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-3\")\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSignatoryPanel))"
+ }
+ },
+ "getSignatoryPanel": {
+ "partial_function_name_raw": "nameOf(getSignatoryPanel)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID\"",
+ "summary": "\"Get Signatory Panel\"",
+ "description": "s\"\"\"Get a specific signatory panel by its ID.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "SignatoryPanelJsonV600(\n panel_id = \"panel-id-001\",\n mandate_id = \"mandate-id-123\",\n panel_name = \"Panel A - Directors\",\n description = \"Board directors authorised to sign\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-3\")\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetSignatoryPanel))"
+ }
+ },
+ "updateSignatoryPanel": {
+ "partial_function_name_raw": "nameOf(updateSignatoryPanel)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID\"",
+ "summary": "\"Update Signatory Panel\"",
+ "description": "s\"\"\"Update a signatory panel.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "UpdateSignatoryPanelJsonV600(\n panel_name = \"Panel A - Updated Directors\",\n description = \"Updated board directors\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-4\")\n )",
+ "success_response_body": "SignatoryPanelJsonV600(\n panel_id = \"panel-id-001\",\n mandate_id = \"mandate-id-123\",\n panel_name = \"Panel A - Updated Directors\",\n description = \"Updated board directors\",\n user_ids = List(\"user-id-1\", \"user-id-2\", \"user-id-4\")\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateSignatoryPanel))"
+ }
+ },
+ "deleteSignatoryPanel": {
+ "partial_function_name_raw": "nameOf(deleteSignatoryPanel)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/mandates/MANDATE_ID/signatory-panels/PANEL_ID\"",
+ "summary": "\"Delete Signatory Panel\"",
+ "description": "s\"\"\"Delete a signatory panel.\n |\n |Authentication is Required\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n $BankNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagMandate)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSignatoryPanel))"
+ }
+ },
+ "createCounterpartyAttribute": {
+ "partial_function_name_raw": "nameOf(createCounterpartyAttribute)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes\"",
+ "summary": "\"Create Counterparty Attribute\"",
+ "description": "s\"\"\"\n | Create a new Counterparty Attribute for a given COUNTERPARTY_ID.\n |\n | The type field must be one of \"STRING\", \"INTEGER\", \"DOUBLE\" or \"DATE_WITH_DAY\".\n | Authentication is Required\n |\n \"\"\".stripMargin",
+ "example_request_body": "counterpartyAttributeRequestJsonV600",
+ "success_response_body": "counterpartyAttributeResponseJsonV600",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError)",
+ "tags": "List(apiTagCounterpartyAttribute, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCounterpartyAttribute))"
+ }
+ },
+ "deleteCounterpartyAttribute": {
+ "partial_function_name_raw": "nameOf(deleteCounterpartyAttribute)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID\"",
+ "summary": "\"Delete Counterparty Attribute\"",
+ "description": "s\"\"\"\n | Delete a Counterparty Attribute specified by COUNTERPARTY_ATTRIBUTE_ID.\n |\n | Authentication is Required\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagCounterpartyAttribute, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCounterpartyAttribute))"
+ }
+ },
+ "getCounterpartyAttributeById": {
+ "partial_function_name_raw": "nameOf(getCounterpartyAttributeById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID\"",
+ "summary": "\"Get Counterparty Attribute By ID\"",
+ "description": "s\"\"\"\n | Get a specific Counterparty Attribute by its COUNTERPARTY_ATTRIBUTE_ID.\n |\n | Authentication is Required\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyAttributeResponseJsonV600",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagCounterpartyAttribute, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCounterpartyAttribute))"
+ }
+ },
+ "getAllCounterpartyAttributes": {
+ "partial_function_name_raw": "nameOf(getAllCounterpartyAttributes)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes\"",
+ "summary": "\"Get All Counterparty Attributes\"",
+ "description": "s\"\"\"\n | Get all attributes for the specified Counterparty.\n |\n | Authentication is Required\n |\n \"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "counterpartyAttributesJsonV600",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, UnknownError)",
+ "tags": "List(apiTagCounterpartyAttribute, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCounterpartyAttributes))"
+ }
+ },
+ "updateCounterpartyAttribute": {
+ "partial_function_name_raw": "nameOf(updateCounterpartyAttribute)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/accounts/ACCOUNT_ID/counterparties/COUNTERPARTY_ID/attributes/COUNTERPARTY_ATTRIBUTE_ID\"",
+ "summary": "\"Update Counterparty Attribute\"",
+ "description": "s\"\"\"\n | Update an existing Counterparty Attribute specified by COUNTERPARTY_ATTRIBUTE_ID.\n |\n | Authentication is Required\n |\n \"\"\".stripMargin",
+ "example_request_body": "counterpartyAttributeRequestJsonV600",
+ "success_response_body": "counterpartyAttributeResponseJsonV600",
+ "error_response_bodies": "List($AuthenticatedUserIsRequired, InvalidJsonFormat, UnknownError)",
+ "tags": "List(apiTagCounterpartyAttribute, apiTagApi)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateCounterpartyAttribute))"
+ }
+ },
+ "createCustomerLink": {
+ "partial_function_name_raw": "nameOf(createCustomerLink)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/customer-links\"",
+ "summary": "\"Create Customer Link\"",
+ "description": "s\"\"\"Link a Customer to another Customer (e.g. spouse, parent, close_associate).\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "postCustomerLinkJsonV600",
+ "success_response_body": "customerLinkJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n CreateCustomerLinkError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canCreateCustomerLink))"
+ }
+ },
+ "getCustomerLinksByCustomerId": {
+ "partial_function_name_raw": "nameOf(getCustomerLinksByCustomerId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/customer-links\"",
+ "summary": "\"Get Customer Links by CUSTOMER_ID\"",
+ "description": "s\"\"\"Get Customer Links by CUSTOMER_ID.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerLinksJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerLinks))"
+ }
+ },
+ "getCustomerLinksByBankId": {
+ "partial_function_name_raw": "nameOf(getCustomerLinksByBankId)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customer-links\"",
+ "summary": "\"Get Customer Links at Bank\"",
+ "description": "s\"\"\"Get all Customer Links at a Bank.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerLinksJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerLinks))"
+ }
+ },
+ "getCustomerLinkById": {
+ "partial_function_name_raw": "nameOf(getCustomerLinkById)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID\"",
+ "summary": "\"Get Customer Link by CUSTOMER_LINK_ID\"",
+ "description": "s\"\"\"Get Customer Link by CUSTOMER_LINK_ID.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "customerLinkJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerLinkNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetCustomerLink))"
+ }
+ },
+ "updateCustomerLink": {
+ "partial_function_name_raw": "nameOf(updateCustomerLink)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID\"",
+ "summary": "\"Update Customer Link\"",
+ "description": "s\"\"\"Update an existing Customer Link.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "putCustomerLinkJsonV600",
+ "success_response_body": "customerLinkJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n InvalidJsonFormat,\n CustomerLinkNotFound,\n UserHasMissingRoles,\n UpdateCustomerLinkError,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canUpdateCustomerLink))"
+ }
+ },
+ "deleteCustomerLink": {
+ "partial_function_name_raw": "nameOf(deleteCustomerLink)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/customer-links/CUSTOMER_LINK_ID\"",
+ "summary": "\"Delete Customer Link\"",
+ "description": "s\"\"\"Delete a Customer Link.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerLinkNotFound,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteCustomerLink))"
+ }
+ },
+ "getCustomerInvestigationReport": {
+ "partial_function_name_raw": "nameOf(getCustomerInvestigationReport)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/customers/CUSTOMER_ID/investigation-report\"",
+ "summary": "\"Get Customer Investigation Report\"",
+ "description": "s\"\"\"Get a Customer Investigation Report for fraud detection, AML (Anti-Money Laundering), and financial crime analysis.\n |\n |This endpoint assembles a comprehensive data package for a customer in a single API call,\n |designed for use by AI agents, compliance officers, and financial crime investigators.\n |\n |**Use Cases:**\n |\n |* Fraud Detection - identify suspicious transaction patterns\n |* AML / Anti-Money Laundering - trace fund flows and flag anomalies\n |* KYC Enhanced Due Diligence - deep-dive into customer activity\n |* Suspicious Activity Report (SAR) preparation\n |* Financial crime investigation and evidence gathering\n |\n |**Data Returned:**\n |\n |* Customer details (legal name, KYC status)\n |* All accounts linked to the customer (with balances)\n |* Transaction history for those accounts (within the specified date range)\n |* Related customers (via customer links) — spouses, associates, business partners\n |\n |**Suspicious Patterns This Data Supports Detecting:**\n |\n |* Money flowing through intermediary companies (A to B to C patterns)\n |* Payments inconsistent with known income or salary\n |* Transfers to related parties (spouses, associates) shortly after large inflows\n |* Round-tripping — money returning to origin via indirect paths\n |* Vague or generic transaction descriptions on large amounts\n |* Structuring — multiple transactions just below reporting thresholds\n |* Rapid movement of funds across accounts (layering)\n |\n |**Query Parameters:**\n |\n |* from_date: Start date for transactions (ISO format, e.g. $DateWithMsExampleString). Defaults to 1 year ago.\n |* to_date: End date for transactions (ISO format, e.g. $DateWithMsExampleString). Defaults to now.\n |* limit: Maximum number of transactions per account (default 500).\n |\n |**Note:** This endpoint is only available in mapped mode (connector=mapped).\n |For other connector configurations, use the individual endpoints to retrieve\n |customer, account, transaction, and customer link data separately.\n |\n |Authentication is Required\n |\n |\"\"\"",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "investigationReportJsonV600",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n $BankNotFound,\n CustomerNotFoundByCustomerId,\n InvestigationReportNotAvailable,\n UserHasMissingRoles,\n UnknownError\n )",
+ "tags": "List(apiTagCustomer, apiTagKyc, apiTagTransaction, apiTagAccount, apiTagFinancialCrime, apiTagAiAgent)",
+ "extra_named_args": {
+ "roles": "Some(List(canGetInvestigationReport))"
+ }
+ },
+ "createBankChatRoom": {
+ "partial_function_name_raw": "nameOf(createBankChatRoom)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms\"",
+ "summary": "\"Create Bank Chat Room\"",
+ "description": "s\"\"\"Create a new chat room scoped to a bank.\n |The creator is automatically added as a participant with all permissions.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatRoomJsonV600(name = \"General Discussion\", description = \"A place to discuss general topics\")",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "createSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(createSystemChatRoom)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms\"",
+ "summary": "\"Create System Chat Room\"",
+ "description": "s\"\"\"Create a new system-level chat room (not scoped to a bank).\n |The creator is automatically added as a participant with all permissions.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatRoomJsonV600(name = \"General Discussion\", description = \"A place to discuss general topics\")",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankChatRooms": {
+ "partial_function_name_raw": "nameOf(getBankChatRooms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms\"",
+ "summary": "\"Get Bank Chat Rooms\"",
+ "description": "s\"\"\"Get all chat rooms for the specified bank that the current user is a participant of.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemChatRooms": {
+ "partial_function_name_raw": "nameOf(getSystemChatRooms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms\"",
+ "summary": "\"Get System Chat Rooms\"",
+ "description": "s\"\"\"Get all system-level chat rooms that the current user is a participant of.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankChatRoom": {
+ "partial_function_name_raw": "nameOf(getBankChatRoom)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Get Bank Chat Room\"",
+ "description": "s\"\"\"Get a specific chat room by ID within a bank. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(getSystemChatRoom)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Get System Chat Room\"",
+ "description": "s\"\"\"Get a specific system-level chat room by ID. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "updateBankChatRoom": {
+ "partial_function_name_raw": "nameOf(updateBankChatRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Update Bank Chat Room\"",
+ "description": "s\"\"\"Update the name and/or description of a chat room. Requires can_update_room permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutChatRoomJsonV600(name = Some(\"Updated Name\"), description = Some(\"Updated description\"))",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"Updated Name\",\n description = \"Updated description\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n InsufficientChatPermission,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "updateSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(updateSystemChatRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Update System Chat Room\"",
+ "description": "s\"\"\"Update the name and/or description of a system-level chat room. Requires can_update_room permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutChatRoomJsonV600(name = Some(\"Updated Name\"), description = Some(\"Updated description\"))",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"Updated Name\",\n description = \"Updated description\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n InsufficientChatPermission,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "deleteBankChatRoom": {
+ "partial_function_name_raw": "nameOf(deleteBankChatRoom)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Delete Bank Chat Room\"",
+ "description": "s\"\"\"Delete a chat room. Requires the CanDeleteBankChatRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteBankChatRoom))"
+ }
+ },
+ "deleteSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(deleteSystemChatRoom)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID\"",
+ "summary": "\"Delete System Chat Room\"",
+ "description": "s\"\"\"Delete a system-level chat room. Requires the CanDeleteSystemChatRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canDeleteSystemChatRoom))"
+ }
+ },
+ "archiveBankChatRoom": {
+ "partial_function_name_raw": "nameOf(archiveBankChatRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/archive-status\"",
+ "summary": "\"Archive Bank Chat Room\"",
+ "description": "s\"\"\"Archive a chat room. Archived rooms cannot receive new messages or participants.\n |Requires the CanArchiveBankChatRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = true,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canArchiveBankChatRoom))"
+ }
+ },
+ "archiveSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(archiveSystemChatRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/archive-status\"",
+ "summary": "\"Archive System Chat Room\"",
+ "description": "s\"\"\"Archive a system-level chat room. Archived rooms cannot receive new messages or participants.\n |Requires the CanArchiveSystemChatRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = true,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canArchiveSystemChatRoom))"
+ }
+ },
+ "setBankChatRoomOpenRoom": {
+ "partial_function_name_raw": "nameOf(setBankChatRoomOpenRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/open-room\"",
+ "summary": "\"Set Chat Room All Users Are Participants\"",
+ "description": "s\"\"\"Set whether all authenticated users are implicit participants of this chat room.\n |\n |If true, all users can read and send messages without needing an explicit Participant record.\n |\n |Requires the CanSetBankChatRoomIsOpenRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"username\",\n created_by_provider = \"provider\",\n is_open_room = true,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canSetBankChatRoomIsOpenRoom))"
+ }
+ },
+ "setSystemChatRoomOpenRoom": {
+ "partial_function_name_raw": "nameOf(setSystemChatRoomOpenRoom)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/open-room\"",
+ "summary": "\"Set System Chat Room All Users Are Participants\"",
+ "description": "s\"\"\"Set whether all authenticated users are implicit participants of this system-level chat room.\n |\n |If true, all users can read and send messages without needing an explicit Participant record.\n |\n |Requires the CanSetSystemChatRoomIsOpenRoom role.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"username\",\n created_by_provider = \"provider\",\n is_open_room = true,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UserHasMissingRoles,\n ChatRoomNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "Some(List(canSetSystemChatRoomIsOpenRoom))"
+ }
+ },
+ "joinBankChatRoom": {
+ "partial_function_name_raw": "nameOf(joinBankChatRoom)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-room-participants\"",
+ "summary": "\"Join Bank Chat Room\"",
+ "description": "s\"\"\"Join a chat room using a joining key (passed as joining_key in the JSON body).\n |The user is added as a participant with no special permissions.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-123\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJoiningKey,\n ChatRoomIsArchived,\n ChatRoomParticipantAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "joinSystemChatRoom": {
+ "partial_function_name_raw": "nameOf(joinSystemChatRoom)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-room-participants\"",
+ "summary": "\"Join System Chat Room\"",
+ "description": "s\"\"\"Join a system-level chat room using a joining key (passed as joining_key in the JSON body).\n |The user is added as a participant with no special permissions.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-123\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJoiningKey,\n ChatRoomIsArchived,\n ChatRoomParticipantAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "refreshBankJoiningKey": {
+ "partial_function_name_raw": "nameOf(refreshBankJoiningKey)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/joining-key\"",
+ "summary": "\"Refresh Bank Chat Room Joining Key\"",
+ "description": "s\"\"\"Refresh the joining key for a chat room. The old key becomes invalid.\n |Requires can_refresh_joining_key permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JoiningKeyJsonV600(joining_key = \"new-key-abc123\")",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n InsufficientChatPermission,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "refreshSystemJoiningKey": {
+ "partial_function_name_raw": "nameOf(refreshSystemJoiningKey)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/joining-key\"",
+ "summary": "\"Refresh System Chat Room Joining Key\"",
+ "description": "s\"\"\"Refresh the joining key for a system-level chat room. The old key becomes invalid.\n |Requires can_refresh_joining_key permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "JoiningKeyJsonV600(joining_key = \"new-key-abc123\")",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n InsufficientChatPermission,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "addBankChatRoomParticipant": {
+ "partial_function_name_raw": "nameOf(addBankChatRoomParticipant)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants\"",
+ "summary": "\"Add Bank Chat Room Participant\"",
+ "description": "s\"\"\"Add a participant to a chat room. Requires can_manage_permissions permission.\n |Specify either user_id or consumer_id, but not both.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostParticipantJsonV600(user_id = Some(\"user-id-456\"), consumer_id = None, permissions = Some(List(\"can_delete_message\")), webhook_url = None)",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-456\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-456\",\n username = \"ellie.y.1.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_delete_message\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n InsufficientChatPermission,\n MustSpecifyUserIdOrConsumerId,\n ChatRoomParticipantAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "addSystemChatRoomParticipant": {
+ "partial_function_name_raw": "nameOf(addSystemChatRoomParticipant)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/participants\"",
+ "summary": "\"Add System Chat Room Participant\"",
+ "description": "s\"\"\"Add a participant to a system-level chat room. Requires can_manage_permissions permission.\n |Specify either user_id or consumer_id, but not both.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostParticipantJsonV600(user_id = Some(\"user-id-456\"), consumer_id = None, permissions = Some(List(\"can_delete_message\")), webhook_url = None)",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-456\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-456\",\n username = \"ellie.y.1.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_delete_message\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n InsufficientChatPermission,\n MustSpecifyUserIdOrConsumerId,\n ChatRoomParticipantAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankChatRoomParticipants": {
+ "partial_function_name_raw": "nameOf(getBankChatRoomParticipants)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants\"",
+ "summary": "\"Get Bank Chat Room Participants\"",
+ "description": "s\"\"\"Get all participants of a chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ParticipantsJsonV600(participants = List(ParticipantJsonV600(\n participant_id = \"participant-id-123\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_update_room\", \"can_delete_message\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemChatRoomParticipants": {
+ "partial_function_name_raw": "nameOf(getSystemChatRoomParticipants)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/participants\"",
+ "summary": "\"Get System Chat Room Participants\"",
+ "description": "s\"\"\"Get all participants of a system-level chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ParticipantsJsonV600(participants = List(ParticipantJsonV600(\n participant_id = \"participant-id-123\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_update_room\", \"can_delete_message\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "updateBankParticipantPermissions": {
+ "partial_function_name_raw": "nameOf(updateBankParticipantPermissions)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants/USER_ID\"",
+ "summary": "\"Update Bank Chat Room Participant Permissions\"",
+ "description": "s\"\"\"Update the permissions of a participant. Requires can_manage_permissions permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutParticipantPermissionsJsonV600(permissions = List(\"can_delete_message\", \"can_update_room\"))",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-456\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-456\",\n username = \"ellie.y.1.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_delete_message\", \"can_update_room\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n InsufficientChatPermission,\n ChatRoomParticipantNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "updateSystemParticipantPermissions": {
+ "partial_function_name_raw": "nameOf(updateSystemParticipantPermissions)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/participants/USER_ID\"",
+ "summary": "\"Update System Chat Room Participant Permissions\"",
+ "description": "s\"\"\"Update the permissions of a participant in a system-level chat room. Requires can_manage_permissions permission.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutParticipantPermissionsJsonV600(permissions = List(\"can_delete_message\", \"can_update_room\"))",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-456\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-456\",\n username = \"ellie.y.1.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(\"can_delete_message\", \"can_update_room\"),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n InsufficientChatPermission,\n ChatRoomParticipantNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "removeBankChatRoomParticipant": {
+ "partial_function_name_raw": "nameOf(removeBankChatRoomParticipant)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/participants/USER_ID\"",
+ "summary": "\"Remove Bank Chat Room Participant\"",
+ "description": "s\"\"\"Remove a participant from a chat room. Requires can_remove_participant permission, or the user can remove themselves.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n InsufficientChatPermission,\n ChatRoomParticipantNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "removeSystemChatRoomParticipant": {
+ "partial_function_name_raw": "nameOf(removeSystemChatRoomParticipant)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/participants/USER_ID\"",
+ "summary": "\"Remove System Chat Room Participant\"",
+ "description": "s\"\"\"Remove a participant from a system-level chat room. Requires can_remove_participant permission, or the user can remove themselves.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n InsufficientChatPermission,\n ChatRoomParticipantNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "sendBankChatMessage": {
+ "partial_function_name_raw": "nameOf(sendBankChatMessage)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages\"",
+ "summary": "\"Send Bank Chat Message\"",
+ "description": "s\"\"\"Send a message in a chat room. The current user must be a participant and the room must not be archived.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatMessageJsonV600(content = \"Hello everyone!\", message_type = Some(\"text\"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None)",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatRoomIsArchived,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "sendSystemChatMessage": {
+ "partial_function_name_raw": "nameOf(sendSystemChatMessage)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages\"",
+ "summary": "\"Send System Chat Message\"",
+ "description": "s\"\"\"Send a message in a system-level chat room. The current user must be a participant and the room must not be archived.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatMessageJsonV600(content = \"Hello everyone!\", message_type = Some(\"text\"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None)",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatRoomIsArchived,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankChatMessages": {
+ "partial_function_name_raw": "nameOf(getBankChatMessages)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages\"",
+ "summary": "\"Get Bank Chat Messages\"",
+ "description": "s\"\"\"Get messages in a chat room.\n |\n |${getObpApiRoot}/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages?limit=50&offset=0&from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString\n |\n |The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List(ReactionSummaryJsonV600(emoji = \"thumbsup\", count = 2, user_ids = List(\"user-1\", \"user-2\")))\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemChatMessages": {
+ "partial_function_name_raw": "nameOf(getSystemChatMessages)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages\"",
+ "summary": "\"Get System Chat Messages\"",
+ "description": "s\"\"\"Get messages in a system-level chat room.\n |\n |${getObpApiRoot}/chat-rooms/CHAT_ROOM_ID/messages?limit=50&offset=0&from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString\n |\n |The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List(ReactionSummaryJsonV600(emoji = \"thumbsup\", count = 2, user_ids = List(\"user-1\", \"user-2\")))\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankChatMessage": {
+ "partial_function_name_raw": "nameOf(getBankChatMessage)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Get Bank Chat Message\"",
+ "description": "s\"\"\"Get a specific message by ID. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemChatMessage": {
+ "partial_function_name_raw": "nameOf(getSystemChatMessage)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Get System Chat Message\"",
+ "description": "s\"\"\"Get a specific message by ID in a system-level chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hello everyone!\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "editBankChatMessage": {
+ "partial_function_name_raw": "nameOf(editBankChatMessage)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Edit Bank Chat Message\"",
+ "description": "s\"\"\"Edit a message. Only the sender can edit their own messages.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutChatMessageJsonV600(content = \"Updated message content\")",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Updated message content\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n CannotEditOthersMessage,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "editSystemChatMessage": {
+ "partial_function_name_raw": "nameOf(editSystemChatMessage)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Edit System Chat Message\"",
+ "description": "s\"\"\"Edit a message in a system-level chat room. Only the sender can edit their own messages.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PutChatMessageJsonV600(content = \"Updated message content\")",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Updated message content\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n CannotEditOthersMessage,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "deleteBankChatMessage": {
+ "partial_function_name_raw": "nameOf(deleteBankChatMessage)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Delete Bank Chat Message\"",
+ "description": "s\"\"\"Soft-delete a message. The sender can delete their own messages, or a participant with can_delete_message permission can delete any message.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n CannotDeleteMessage,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "deleteSystemChatMessage": {
+ "partial_function_name_raw": "nameOf(deleteSystemChatMessage)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID\"",
+ "summary": "\"Delete System Chat Message\"",
+ "description": "s\"\"\"Soft-delete a message in a system-level chat room. The sender can delete their own messages, or a participant with can_delete_message permission can delete any message.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n CannotDeleteMessage,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankThreadReplies": {
+ "partial_function_name_raw": "nameOf(getBankThreadReplies)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread\"",
+ "summary": "\"Get Bank Thread Replies\"",
+ "description": "s\"\"\"Get all replies in a message thread. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(\n chat_message_id = \"reply-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-456\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"This is a reply\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"msg-id-123\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemThreadReplies": {
+ "partial_function_name_raw": "nameOf(getSystemThreadReplies)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread\"",
+ "summary": "\"Get System Thread Replies\"",
+ "description": "s\"\"\"Get all replies in a message thread in a system-level chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(\n chat_message_id = \"reply-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-456\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"This is a reply\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"msg-id-123\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "replyInBankThread": {
+ "partial_function_name_raw": "nameOf(replyInBankThread)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread\"",
+ "summary": "\"Reply In Bank Thread\"",
+ "description": "s\"\"\"Reply to a message in a thread. The current user must be a participant and the room must not be archived.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatMessageJsonV600(content = \"This is a thread reply\", message_type = Some(\"text\"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None)",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"reply-id-456\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"This is a thread reply\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"msg-id-123\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatRoomIsArchived,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "replyInSystemThread": {
+ "partial_function_name_raw": "nameOf(replyInSystemThread)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/thread\"",
+ "summary": "\"Reply In System Thread\"",
+ "description": "s\"\"\"Reply to a message in a thread in a system-level chat room. The current user must be a participant and the room must not be archived.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostChatMessageJsonV600(content = \"This is a thread reply\", message_type = Some(\"text\"), mentioned_user_ids = None, reply_to_message_id = None, thread_id = None)",
+ "success_response_body": "ChatMessageJsonV600(\n chat_message_id = \"reply-id-456\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-123\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"This is a thread reply\",\n message_type = \"text\",\n mentioned_user_ids = List(),\n reply_to_message_id = \"\",\n thread_id = \"msg-id-123\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatRoomIsArchived,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "addBankReaction": {
+ "partial_function_name_raw": "nameOf(addBankReaction)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions\"",
+ "summary": "\"Add Bank Reaction\"",
+ "description": "s\"\"\"Add a reaction (emoji) to a message. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostReactionJsonV600(emoji = \"thumbsup\")",
+ "success_response_body": "ReactionJsonV600(\n reaction_id = \"reaction-id-123\",\n chat_message_id = \"msg-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n emoji = \"thumbsup\",\n created_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n ReactionAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "addSystemReaction": {
+ "partial_function_name_raw": "nameOf(addSystemReaction)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions\"",
+ "summary": "\"Add System Reaction\"",
+ "description": "s\"\"\"Add a reaction (emoji) to a message in a system-level chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "PostReactionJsonV600(emoji = \"thumbsup\")",
+ "success_response_body": "ReactionJsonV600(\n reaction_id = \"reaction-id-123\",\n chat_message_id = \"msg-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n emoji = \"thumbsup\",\n created_at = new java.util.Date()\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n ReactionAlreadyExists,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "removeBankReaction": {
+ "partial_function_name_raw": "nameOf(removeBankReaction)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions/EMOJI\"",
+ "summary": "\"Remove Bank Reaction\"",
+ "description": "s\"\"\"Remove your own reaction from a message.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n ReactionNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "removeSystemReaction": {
+ "partial_function_name_raw": "nameOf(removeSystemReaction)",
+ "request_verb": "\"DELETE\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions/EMOJI\"",
+ "summary": "\"Remove System Reaction\"",
+ "description": "s\"\"\"Remove your own reaction from a message in a system-level chat room.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n ReactionNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankReactions": {
+ "partial_function_name_raw": "nameOf(getBankReactions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions\"",
+ "summary": "\"Get Bank Reactions\"",
+ "description": "s\"\"\"Get all reactions for a message. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ReactionsJsonV600(reactions = List(ReactionJsonV600(\n reaction_id = \"reaction-id-123\",\n chat_message_id = \"msg-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n emoji = \"thumbsup\",\n created_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemReactions": {
+ "partial_function_name_raw": "nameOf(getSystemReactions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/CHAT_MESSAGE_ID/reactions\"",
+ "summary": "\"Get System Reactions\"",
+ "description": "s\"\"\"Get all reactions for a message in a system-level chat room. The current user must be a participant.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ReactionsJsonV600(reactions = List(ReactionJsonV600(\n reaction_id = \"reaction-id-123\",\n chat_message_id = \"msg-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n emoji = \"thumbsup\",\n created_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n ChatMessageNotFound,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "signalBankTyping": {
+ "partial_function_name_raw": "nameOf(signalBankTyping)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/typing-indicators\"",
+ "summary": "\"Signal Bank Typing\"",
+ "description": "s\"\"\"Signal that the current user is typing in a chat room. The typing indicator expires after 5 seconds.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "signalSystemTyping": {
+ "partial_function_name_raw": "nameOf(signalSystemTyping)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/typing-indicators\"",
+ "summary": "\"Signal System Typing\"",
+ "description": "s\"\"\"Signal that the current user is typing in a system-level chat room. The typing indicator expires after 5 seconds.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "EmptyBody",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBankTypingUsers": {
+ "partial_function_name_raw": "nameOf(getBankTypingUsers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/banks/BANK_ID/chat-rooms/CHAT_ROOM_ID/typing-indicators\"",
+ "summary": "\"Get Bank Typing Users\"",
+ "description": "s\"\"\"Get the list of users currently typing in a chat room.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "TypingUsersJsonV600(users = List(TypingUserJsonV600(user_id = \"user-id-123\", username = \"robert.x.0.gh\", provider = \"https://github.com\")))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getSystemTypingUsers": {
+ "partial_function_name_raw": "nameOf(getSystemTypingUsers)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/typing-indicators\"",
+ "summary": "\"Get System Typing Users\"",
+ "description": "s\"\"\"Get the list of users currently typing in a system-level chat room.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "TypingUsersJsonV600(users = List(TypingUserJsonV600(user_id = \"user-id-123\", username = \"robert.x.0.gh\", provider = \"https://github.com\")))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getMyChatRooms": {
+ "partial_function_name_raw": "nameOf(getMyChatRooms)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/chat-rooms\"",
+ "summary": "\"Get My Chat Rooms\"",
+ "description": "s\"\"\"Get all chat rooms the current user is a participant of, across all banks and system-level rooms.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"gh.29.uk\",\n name = \"General Discussion\",\n description = \"A place to discuss general topics\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-123\",\n created_by_username = \"robert.x.0.gh\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello everyone!\"),\n last_message_sender_username =Some(\"robert.x.0.gh\"),\n unread_count = Some(3),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "searchChatRooms": {
+ "partial_function_name_raw": "nameOf(searchChatRooms)",
+ "request_verb": "\"POST\"",
+ "request_url": "\"/chat-rooms/search\"",
+ "summary": "\"Search Chat Rooms\"",
+ "description": "s\"\"\"Search chat rooms the current user is a participant of, filtered by the supplied criteria.\n |\n |Currently supports filtering by participant set:\n |\n |- `with_user_ids` (array of user_id strings, required): only return rooms where the current user\n | AND every listed user_id are participants. Pass an empty list to match all of the current user's rooms.\n |- `exact_participants` (boolean, optional, default `false`): if `true`, the room's participant set\n | must equal exactly `{current user} ∪ with_user_ids` with no extras. Open rooms are excluded\n | from exact-participant searches because their participant set is implicitly \"everyone\".\n |\n |Primary use case: a client looking up an existing 1-on-1 direct-message room before creating one,\n |by calling with `with_user_ids: []` and `exact_participants: true`.\n |\n |The response shape is the same as `Get My Chat Rooms`.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "ChatRoomSearchRequestJsonV600(\n with_user_ids = List(\"user-id-123\"),\n exact_participants = Some(true)\n )",
+ "success_response_body": "ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(\n chat_room_id = \"chat-room-id-123\",\n bank_id = \"\",\n name = \"DM with robert.x.0.gh\",\n description = \"\",\n joining_key = \"abc123key\",\n created_by_user_id = \"user-id-456\",\n created_by_username = \"alice\",\n created_by_provider = \"https://github.com\",\n is_open_room = false,\n is_archived = false,\n last_message_at = Some(new java.util.Date()),\n last_message_preview = Some(\"Hello!\"),\n last_message_sender_username =Some(\"alice\"),\n unread_count = Some(0),\n created_at = new java.util.Date(),\n updated_at = new java.util.Date()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n InvalidJsonFormat,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getMyUnreadCounts": {
+ "partial_function_name_raw": "nameOf(getMyUnreadCounts)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/chat-rooms/unread\"",
+ "summary": "\"Get My Unread Counts\"",
+ "description": "s\"\"\"Get unread message counts for all chat rooms the current user is a participant of.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "UnreadCountsJsonV600(unread_counts = List(UnreadCountJsonV600(chat_room_id = \"chat-room-id-123\", unread_count = 5)))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "markChatRoomRead": {
+ "partial_function_name_raw": "nameOf(markChatRoomRead)",
+ "request_verb": "\"PUT\"",
+ "request_url": "\"/users/current/chat-rooms/CHAT_ROOM_ID/read-marker\"",
+ "summary": "\"Mark Chat Room Read\"",
+ "description": "s\"\"\"Mark all messages in a chat room as read for the current user by updating lastReadAt to now.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ParticipantJsonV600(\n participant_id = \"participant-id-123\",\n chat_room_id = \"chat-room-id-123\",\n user_id = \"user-id-123\",\n username = \"robert.x.0.gh\",\n provider = \"https://github.com\",\n consumer_id = \"\",\n consumer_name = \"\",\n permissions = List(),\n webhook_url = \"\",\n joined_at = new java.util.Date(),\n last_read_at = new java.util.Date(),\n is_muted = false\n )",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getMyMentions": {
+ "partial_function_name_raw": "nameOf(getMyMentions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/users/current/mentions\"",
+ "summary": "\"Get My Mentions\"",
+ "description": "s\"\"\"Get messages where the current user is mentioned. Supports limit and offset query parameters.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "ChatMessagesJsonV600(messages = List(ChatMessageJsonV600(\n chat_message_id = \"msg-id-123\",\n chat_room_id = \"chat-room-id-123\",\n sender_user_id = \"user-id-456\",\n sender_consumer_id = \"\",\n sender_username = \"robert.x.0.gh\",\n sender_provider = \"https://github.com\",\n sender_consumer_name = \"My Banking App\",\n content = \"Hey @user-id-123, check this out!\",\n message_type = \"text\",\n mentioned_user_ids = List(\"user-id-123\"),\n reply_to_message_id = \"\",\n thread_id = \"\",\n is_deleted = false,\n created_at = new java.util.Date(),\n updated_at = new java.util.Date(),\n reactions = List()\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ },
+ "getBulkReactions": {
+ "partial_function_name_raw": "nameOf(getBulkReactions)",
+ "request_verb": "\"GET\"",
+ "request_url": "\"/chat-rooms/CHAT_ROOM_ID/messages/reactions\"",
+ "summary": "\"Get Bulk Reactions\"",
+ "description": "s\"\"\"Get reactions for multiple messages in a single request.\n |\n |Pass message IDs as a comma-separated query parameter: ?message_ids=id1,id2,id3\n |\n |Returns reactions grouped by message ID.\n |\n |Authentication is Required\n |\n |\"\"\".stripMargin",
+ "example_request_body": "EmptyBody",
+ "success_response_body": "BulkReactionsJsonV600(message_reactions = List(MessageReactionsJsonV600(\n chat_message_id = \"msg-id-123\",\n reactions = List(ReactionSummaryJsonV600(emoji = \"thumbsup\", count = 2, user_ids = List(\"user-1\", \"user-2\")))\n )))",
+ "error_response_bodies": "List(\n $AuthenticatedUserIsRequired,\n ChatRoomNotFound,\n NotChatRoomParticipant,\n UnknownError\n )",
+ "tags": "List(apiTagChat)",
+ "extra_named_args": {
+ "roles": "None"
+ }
+ }
+ }
+}
diff --git a/scripts/resource_doc_baseline/parity_allowlist.json b/scripts/resource_doc_baseline/parity_allowlist.json
new file mode 100644
index 0000000000..ad9359f23a
--- /dev/null
+++ b/scripts/resource_doc_baseline/parity_allowlist.json
@@ -0,0 +1,1217 @@
+{
+ "schema_version": 1,
+ "rename_pairs": [
+ {
+ "version": "v2_1_0",
+ "lift_name": "addCardsForBank",
+ "http4s_name": "addCardForBank",
+ "reason": "Renamed during http4s migration (plural -> singular); same POST /banks/BANK_ID/cards endpoint",
+ "lift_identity_digest": "2489414a4e028dfd96561e799236ee005f5e053c2beaff2cb851a28ae5132c2f",
+ "http4s_identity_digest": "2489414a4e028dfd96561e799236ee005f5e053c2beaff2cb851a28ae5132c2f"
+ },
+ {
+ "version": "v5_1_0",
+ "lift_name": "createConsentImplicit",
+ "http4s_name": "createConsent",
+ "reason": "Renamed during http4s migration (Implicit qualifier dropped); same POST /my/consents/IMPLICIT endpoint",
+ "lift_identity_digest": "c02bfcf72b542dc309204ecebda8155e0bdbafdc6d9515cd609c1e3ec87f1969",
+ "http4s_identity_digest": "c02bfcf72b542dc309204ecebda8155e0bdbafdc6d9515cd609c1e3ec87f1969"
+ }
+ ],
+ "only_in_lift": [
+ {
+ "version": "v2_1_0",
+ "endpoint": "createTransactionRequestCounterparty",
+ "reason": "COUNTERPARTY transaction-request type variant retired from the v2.1.0 http4s surface; superseded by newer-version transaction-request endpoints",
+ "identity_digest": "c59853d817f9e8334eca95f295d4fc803c908a0d9261e713d822c2b1314d3985"
+ },
+ {
+ "version": "v2_1_0",
+ "endpoint": "createTransactionRequestFreeForm",
+ "reason": "FREE_FORM transaction-request type variant retired from the v2.1.0 http4s surface",
+ "identity_digest": "15442f69a71f79960fd182727b90bfc44e2ca1364884489fe275c9a0807c4937"
+ },
+ {
+ "version": "v2_1_0",
+ "endpoint": "createTransactionRequestSandboxTan",
+ "reason": "SANDBOX_TAN transaction-request type variant retired from the v2.1.0 http4s surface; http4s v2.1.0 keeps a generic createTransactionRequest instead",
+ "identity_digest": "5a22860803dd4b940ef818f59b59d563398e92bf62540b431624426e039d75a1"
+ },
+ {
+ "version": "v2_1_0",
+ "endpoint": "createTransactionRequestSepa",
+ "reason": "SEPA transaction-request type variant retired from the v2.1.0 http4s surface",
+ "identity_digest": "6997d91d6b25fdd28a7b6b73ab81c07fdfd297095da796fd4fd8832e54366a11"
+ }
+ ],
+ "only_in_http4s": [
+ {
+ "version": "v2_1_0",
+ "endpoint": "createTransactionRequest",
+ "reason": "Generic http4s v2.1.0 createTransactionRequest replaces the per-type Lift variants (COUNTERPARTY/FREE_FORM/SANDBOX_TAN/SEPA) with one endpoint keyed by a GRANT_VIEW_ID template variable",
+ "identity_digest": "25a8fbc231f1c00856a8ecd8b208b154489fff97595fafd5b9c37a70f39efb0a"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createBankLevelDynamicEntity",
+ "reason": "New in http4s v4.0.0, no Lift predecessor: bank-level dynamic entity creation",
+ "identity_digest": "aa7306a25d88e7df6ce7fa6da0acafa9249a684e22d1e7889c7f4c84663581da"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createSystemDynamicEntity",
+ "reason": "New in http4s v4.0.0, no Lift predecessor: system-level dynamic entity creation",
+ "identity_digest": "46440bce5d9cf100fd14f61894ca6c2377ca996f1988cc125f781495ad25b780"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "updateBankLevelDynamicEntity",
+ "reason": "New in http4s v4.0.0, no Lift predecessor: bank-level dynamic entity update",
+ "identity_digest": "85ab9abe7952c0a22217b5af5728f8fe4da2e9734193a09e381246a477e9f79c"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "updateMyDynamicEntity",
+ "reason": "New in http4s v4.0.0, no Lift predecessor: user-level dynamic entity update",
+ "identity_digest": "f63ba06e281f0bb37a6690a1dcad81cf307efd11ca52eedb8cd6961619e7a136"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "updateSystemDynamicEntity",
+ "reason": "New in http4s v4.0.0, no Lift predecessor: system-level dynamic entity update",
+ "identity_digest": "1a063aacee0d3755f92c5eecf639307106d7cbda22f18e5db539845ec145cc69"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "getBanks",
+ "reason": "New in http4s v5.0.0, no Lift predecessor",
+ "identity_digest": "0c0073bfd65b757d2c2cbe055d6114e000aa34d0c62d58a4e3dce61e374ecad2"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "getProduct",
+ "reason": "New in http4s v5.0.0, no Lift predecessor",
+ "identity_digest": "ce968619327cdde42204fcf1b4a2848955b330e5604f4ff51fcc3f62e4fce033"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "getProducts",
+ "reason": "New in http4s v5.0.0, no Lift predecessor",
+ "identity_digest": "44688378313bff70cacf4fc60468cb8dc3c4194bfe65953dc30aa45389a5f902"
+ },
+ {
+ "version": "v5_1_0",
+ "endpoint": "authoriseUKConsent",
+ "reason": "New in http4s v5.1.0, no Lift predecessor: UK Open Banking consent authorisation (SCA)",
+ "identity_digest": "b0d8ddad27d7da4ae2ead23364b278c3ce3efae511539e3ed5972b6338d95bc5"
+ },
+ {
+ "version": "v5_1_0",
+ "endpoint": "authoriseUKConsentChallenge",
+ "reason": "New in http4s v5.1.0, no Lift predecessor: UK Open Banking consent authorisation challenge (OTP)",
+ "identity_digest": "e347f03f48a1a3f3aeb9933659b7c75ada943fb1a2331cda4b088ced1145ab7b"
+ },
+ {
+ "version": "v5_1_0",
+ "endpoint": "getBanks",
+ "reason": "New in http4s v5.1.0, no Lift predecessor",
+ "identity_digest": "0c0073bfd65b757d2c2cbe055d6114e000aa34d0c62d58a4e3dce61e374ecad2"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createWebUiProps",
+ "reason": "New in http4s v6.0.0, no Lift predecessor",
+ "identity_digest": "14a08784273c1af4165296c2f246d7544e5aae28208a5f02591b115aa032623e"
+ }
+ ],
+ "field_mismatches": [
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteExplicitCounterparty",
+ "field": "requestVerb",
+ "reason": "Lift's doc wrongly listed POST for a delete operation; http4s DELETE is the correct verb (RESTful bug fix)",
+ "lift_digest": "e46d3ae943664116b752137af856edb5f377c6d8012a39e3ef7f39f80a802cac",
+ "http4s_digest": "a5655ec6126f28a76720a61f3e0a6eff066cff954c4003c3dc6def846451db76"
+ },
+ {
+ "version": "v5_1_0",
+ "endpoint": "revokeMyConsent",
+ "field": "requestVerb",
+ "reason": "Lift's doc used inconsistent casing (\"Delete\"); http4s DELETE matches the actual HTTP verb",
+ "lift_digest": "b26de372b4b0eaac60202884a72db98a6be6e9036e785ea867ea01c5f7921098",
+ "http4s_digest": "a5655ec6126f28a76720a61f3e0a6eff066cff954c4003c3dc6def846451db76"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createBankLevelDynamicEntity",
+ "field": "exampleRequestBody",
+ "reason": "http4s example JSON schema shows more field-level ACL properties (indexed/write_role_required/write_role/read_role_required/read_role) documenting features added after the Lift example was written",
+ "lift_digest": "12358da4874cc249de326eda073e5abaf943936049ea3304889c8997cefb004d",
+ "http4s_digest": "b02d422e514e88338bcbb469bea59e068515d19f888a8b43bba9daba215a4319"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createBankLevelDynamicEntity",
+ "field": "successResponseBody",
+ "reason": "Same schema-example enrichment as its exampleRequestBody sibling",
+ "lift_digest": "dba0b1e9992bbd7a883412d8d71f671b457b26e95d8e713d5945b6f74fcb1446",
+ "http4s_digest": "61b2aca2a9079a7707d10c856d02f2ffd99cd8557b76eaa7b177d00455f2a45c"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createSystemDynamicEntity",
+ "field": "exampleRequestBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "12358da4874cc249de326eda073e5abaf943936049ea3304889c8997cefb004d",
+ "http4s_digest": "b02d422e514e88338bcbb469bea59e068515d19f888a8b43bba9daba215a4319"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createSystemDynamicEntity",
+ "field": "successResponseBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "4fce8fffae95f1b3dca1d79feea13c84f40b85907aca358a03b2985435aa665c",
+ "http4s_digest": "75788e83e165d9b5abd1f9add45afb5f65cbfb17f9e732eda4d3353df388b845"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateBankLevelDynamicEntity",
+ "field": "exampleRequestBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "8969bb6fdf996b8d7a6a205194943443da49e6818f337dcb362319e8ad3f7ba4",
+ "http4s_digest": "fa95539cf3af3d8a9e502c790505c4437120e4b96461f942c880f0f25960d770"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateBankLevelDynamicEntity",
+ "field": "successResponseBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "fb39e7460ca2805f706bb8ac37ae375df3195a146a4fd4f1423670c60068c460",
+ "http4s_digest": "30f9e1b59a65ab6d20447ad8ff2e417fcd34c418a6c0b935db7b39daadb64828"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateMyDynamicEntity",
+ "field": "exampleRequestBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "8969bb6fdf996b8d7a6a205194943443da49e6818f337dcb362319e8ad3f7ba4",
+ "http4s_digest": "fa95539cf3af3d8a9e502c790505c4437120e4b96461f942c880f0f25960d770"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateMyDynamicEntity",
+ "field": "successResponseBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "30dea326337d124762eb3a45a7e36bdd6307858b4acca6c765144f7e11cce19e",
+ "http4s_digest": "92739c84cab456c0d5933c5c7c255439134982c9edaa84c741621936eb8a05ba"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateSystemDynamicEntity",
+ "field": "exampleRequestBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "8969bb6fdf996b8d7a6a205194943443da49e6818f337dcb362319e8ad3f7ba4",
+ "http4s_digest": "fa95539cf3af3d8a9e502c790505c4437120e4b96461f942c880f0f25960d770"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateSystemDynamicEntity",
+ "field": "successResponseBody",
+ "reason": "Same schema-example enrichment pattern as createBankLevelDynamicEntity",
+ "lift_digest": "30dea326337d124762eb3a45a7e36bdd6307858b4acca6c765144f7e11cce19e",
+ "http4s_digest": "92739c84cab456c0d5933c5c7c255439134982c9edaa84c741621936eb8a05ba"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAccountDirectory",
+ "field": "successResponseBody",
+ "reason": "account_routings example type updated from the retired FastFirehoseRoutings shape to the current AccountRoutingJsonV121 shape, matching what the endpoint actually returns",
+ "lift_digest": "a731dc9dc5694b48e40fb020a937af6e748d5deabbe3dc42394dfd076d600a42",
+ "http4s_digest": "c2cf57a9b35bb8e84b08116a0fb76a02dac4579faa29de3495960e9a21ebd681"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAggregateMetrics",
+ "field": "successResponseBody",
+ "reason": "Example type name updated from the v3.0.0-era aggregateMetricsJSONV300 to the current v6.0.0 aggregateMetricJsonV600 naming convention",
+ "lift_digest": "99c94399498c012a60c8f2a3982127a223c6edbcd6828f70ecd2a40950042b9d",
+ "http4s_digest": "8ae6de43be70acf76b41fe63e0261e02546e46129e6eeab3a53051b5bbf811e0"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getGroupEntitlements",
+ "field": "successResponseBody",
+ "reason": "Field renamed for clarity: process: Option[String] -> created_by_process: String",
+ "lift_digest": "3d55ed555557072dd24ed04bf49a7eeb8f48dcc1fb53ec219a5289da3203085b",
+ "http4s_digest": "49437a835a7f4ffd355ae0bc76fbc45507fc6a20feca00ca6f6292188da40b14"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "resetPasswordUrl",
+ "field": "summary",
+ "reason": "Wording tweak: \"Send Email\" -> \"Send by Email\"",
+ "lift_digest": "236476344a07802368d79d1c55fde730bf55bec5011e04f623529ef42e2d2de2",
+ "http4s_digest": "6632a5a75a9f2013add36c2c15ab08caab0a36848b805cb1d1c3b9c4ce81749b"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "resetPasswordUrl",
+ "field": "successResponseBody",
+ "reason": "Response redesigned for security: no longer echoes the raw reset URL in the API response body (ResetPasswordUrlJsonV600), instead confirms delivery only (ResetPasswordEmailSentJsonV600 status+to) since the URL is sent by email",
+ "lift_digest": "cb3f6f29cd8711ac89badeec1ac62f89c578a7eade9f36bdfe9ba0edf12aa444",
+ "http4s_digest": "afd0caab8f6b023367e1742719a7bc65d6d6bc734fec8c121ec6432250995ac8"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addCounterpartyMoreInfo",
+ "field": "description",
+ "reason": "Typo fix: \"perpestive\"->\"perspective\", \"counter party\"->\"counterparty\".",
+ "lift_digest": "48df4b08f5ebf314618db2a42265e2a047e664240828a80cfadd4f349e32265a",
+ "http4s_digest": "15a6614589916c33bc84247d10f66e29aab0236490d0fb28abc76bf81e702d2a"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addCounterpartyOpenCorporatesUrl",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "7800e24b40933e1ff7fb307910b8323651e04035b44fe668a5f863ec49ee63cb",
+ "http4s_digest": "37a80c382c77ecb996e2e70905760655ae38460cb19dab35b11e0a4ea42ef6d1"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addCounterpartyPublicAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "fb690d675c1572cc32c0044c435a434f516769717e7bae392eba62e30a569c57",
+ "http4s_digest": "70625637e3c2122bc67d72ebc7a1576a07f89dbca71b13223a43a8f2f297b6ef"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addCounterpartyPublicAlias",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "8e6b933943bcb0841b678881492d54dbecc9a4ab4ed872e9d3b076cf26fb7c6b",
+ "http4s_digest": "2d8dbf4f30316a46c363a8c46a61da63a9fcffad53af51266bbdf2e841ff016a"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addOtherAccountPrivateAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "67de055c35766cac190351999913d89d81058661b54a4f602d66999b9e9aae0c",
+ "http4s_digest": "d13f59a73ff9c8983964e4e43befe11bad83531696b18ee5b1f8e826e130f96e"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addPermissionForUserForBankAccountForOneView",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route. (ACCOUNT_ID/VIEW_ID -> BANK_ACCOUNT_ID/GRANT_VIEW_ID)",
+ "lift_digest": "f1a5ceefc4a1fd9b891e9543f8a39bae0518229744d3a1f94fc4b07aea32d47e",
+ "http4s_digest": "b8fd69e5333ec06e3e7ee3df67ea52fe682fda6d301f176c77decf6f3b63ca09"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addTransactionNarrative",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "491951d96369f48046b63a46f97972a77aa384aaf99862bce960e0453e4742dc",
+ "http4s_digest": "371fe5c23a8981c5d94bf62aab43dceda330872db8390209c312995ad1a7a396"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "addTransactionNarrative",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "219c5ead06fe720f59e87ddf4550c060b70c7c1cbcb0d738c7489445c9a1796e",
+ "http4s_digest": "a12683aa13bafb349a69332a382fa3b613f67592c7eea2cef9424053a0deade3"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "createViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route. (ACCOUNT_ID -> BANK_ACCOUNT_ID)",
+ "lift_digest": "91d541e4991471ff3b872dabd9b68fe6bc29b979fc91df495643a3bd361c0d60",
+ "http4s_digest": "48eb6cec7bca0cd448d5a206ac9bfc211f62c75db93235032dd09a9ead719de9"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteCounterpartyImageUrl",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "03874bf0b9ffdc9efb2d3127db59563174dfa562b545f42ef57360d3e625d060",
+ "http4s_digest": "12ad62cb53de1ed64537da486e94cc24fab901e301123e5f601fcd17fade09b3"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteCounterpartyPrivateAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "5f0dce05efeb0f88e03057f560ce939464af39f34ff71d65ed55efb47e551248",
+ "http4s_digest": "6be8b754d16f1cfd2d09b047ced5cb17856a12730a011cc771d652c265fc6d3b"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteCounterpartyPublicAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "0c3feaf3c9855c5a1777bab1fd73a0a0b47e7afdf689539d4d577d78ae9a22e1",
+ "http4s_digest": "b5f0dd9338389d87715f48f71a41df6129a3ba4e6c3e3b7d51241bd82142883e"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteCounterpartyPublicAlias",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "fd3b564f0a9efb185dab944ddb2a20e0290e83b921acddfa6c7e9df1cd93fa06",
+ "http4s_digest": "0f3c82e1ed1da033932c44a4bf00a8463ea1d51f8c3bbde7f87c8440ff5457c4"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteTagForViewOnTransaction",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "d04e11db56936459e99048c613c3820027230feb388ad8aec18050969a5445e8",
+ "http4s_digest": "915c45a6b6f52af47079425b883d431fa702e42cbdfa5a60b9a109201ea853a3"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "deleteViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "7ff8ab9d5f5380b422cd7e8e46bc1a4beaa86e5eec2aea467285384a2593404a",
+ "http4s_digest": "04e78c3b02fef79fb86ea5555090669801dc4b0dec7ea8fdb1d95de1553d472b"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getOtherAccountByIdForBankAccount",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "09d35c2ef09c2f3f6b1265b5f135d2a12bfc2a253ff0dbad6523d5cf907f33f4",
+ "http4s_digest": "5eed1fbc7ad89a78c45028f625e0c98ba971b85d3fc422fa982b3b740b117715"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getOtherAccountByIdForBankAccount",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "edd1d3001f6969196bfdb42134be81735f1d78b74fdab9e47a7821061bdd6b4e",
+ "http4s_digest": "c2bd6aa796b42db71e8632b789921f9a43e424e5c0d63adda61cc65a62665205"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getOtherAccountForTransaction",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "edd1d3001f6969196bfdb42134be81735f1d78b74fdab9e47a7821061bdd6b4e",
+ "http4s_digest": "c2bd6aa796b42db71e8632b789921f9a43e424e5c0d63adda61cc65a62665205"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getOtherAccountPrivateAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "3de650955e69360b443d7ef7e343a48101ffb79b86aaf941f7c28d451a8354d4",
+ "http4s_digest": "10b6013eac75de3d94f4b8d36e73abfee850225129b903330d07aa9cd42e33c6"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getTagsForViewOnTransaction",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "311bd8e8d58266a4a4a00b4edc9c9f42c138113e78ff9a5f151ea3c46862f7df",
+ "http4s_digest": "126a2f01634ce256a1898464f617b6dc4a644740000fb5ddfb00c69e8acf2f38"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getTransactionByIdForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "ecabd6bfbde5f98c5da6e0413ffde0dcd617fdcc166fecd2803ee3b554f960cb",
+ "http4s_digest": "2e20911e48ab9772e4e13bc1f2d29ff32970bed6e724ac92d4e6c18284a57284"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getTransactionNarrative",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "311bd8e8d58266a4a4a00b4edc9c9f42c138113e78ff9a5f151ea3c46862f7df",
+ "http4s_digest": "126a2f01634ce256a1898464f617b6dc4a644740000fb5ddfb00c69e8acf2f38"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getTransactionsForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "73dc537489a60231085b37593010bc93359c2ad4b06e6a5ac7173a27142290bf",
+ "http4s_digest": "d7baff984c5e02a1f06124418933c95ad8fb2e530a3ca654751fbcf80a57d4da"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "getWhereTagForViewOnTransaction",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "311bd8e8d58266a4a4a00b4edc9c9f42c138113e78ff9a5f151ea3c46862f7df",
+ "http4s_digest": "126a2f01634ce256a1898464f617b6dc4a644740000fb5ddfb00c69e8acf2f38"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "publicAccountsAtOneBank",
+ "field": "errorResponseBodies",
+ "reason": "Lift's own doc self-contradicted (titled \"Anonymous access\", text said \"OAuth not required\", yet still listed AuthenticatedUserIsRequired); http4s removed the contradictory entry to match the documented anonymous behavior.",
+ "lift_digest": "61ff620adb6336c3a7c4c28f758678ddeba477e465318974705a3930e399ce08",
+ "http4s_digest": "2a5c6f70f7dfd24677ad2bfb3c3a69512f12336f6f7cb9084fce8d681f8b8fea"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateCounterpartyImageUrl",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "c4b5be6aaa6cd8c0c547e3a048c7fef428fe5474c67efd0d6a66fc54e7b1a871",
+ "http4s_digest": "e8ea2f8c0afb29c0e0e9daa835156f7ade0dd27899510739f1d7c08d7d2c008d"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateCounterpartyMoreInfo",
+ "field": "description",
+ "reason": "Typo fix, same pattern as addCounterpartyMoreInfo.",
+ "lift_digest": "3362535f561ad61e3818b18abdfdc3b1381db78ebb33e657fa0eec8d5e2e4c51",
+ "http4s_digest": "3025ecfd6fe10dcda43a56de6ac9e36e4a9e38bea21544fc6854aee628465798"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateCounterpartyPrivateAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "b078053afc69a1b1a22ce9a1ca0151c1a4f8f5c36ef8400ba84d6c54d7587f2c",
+ "http4s_digest": "b919050bf14fdaf9582d1c91a4027190b106bfcd5f0c4e321fb5a2c4662aee83"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateCounterpartyPublicAlias",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "705c7c0b079cb48311a40bb9cfaef8eb05ea3cc6b2c080b50839ee0da7b88bec",
+ "http4s_digest": "cca062fc7b422a4e2a4cf052bf08e3b5b1f64c52734fb1c1ef2099de80c9b7dc"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateTransactionNarrative",
+ "field": "errorResponseBodies",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "219c5ead06fe720f59e87ddf4550c060b70c7c1cbcb0d738c7489445c9a1796e",
+ "http4s_digest": "a12683aa13bafb349a69332a382fa3b613f67592c7eea2cef9424053a0deade3"
+ },
+ {
+ "version": "v1_2_1",
+ "endpoint": "updateViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "7ff8ab9d5f5380b422cd7e8e46bc1a4beaa86e5eec2aea467285384a2593404a",
+ "http4s_digest": "04e78c3b02fef79fb86ea5555090669801dc4b0dec7ea8fdb1d95de1553d472b"
+ },
+ {
+ "version": "v1_4_0",
+ "endpoint": "getTransactionRequestTypes",
+ "field": "errorResponseBodies",
+ "reason": "Dropped error strings (\"account not found at bank\" / \"user does not have access to owner view\") are never thrown by any code path in the repo -- dead text carried over in the Lift doc, not a real error the endpoint could return.",
+ "lift_digest": "8c5828c463304c3fcb69cda98086bcff545babae1545868b54b20af7803a5990",
+ "http4s_digest": "e1f18afff1272cce9d549efeea6fbea5784789c38d46bee6c54168f4a4a5ac15"
+ },
+ {
+ "version": "v2_0_0",
+ "endpoint": "createAccount",
+ "field": "requestUrl",
+ "reason": "ACCOUNT_ID -> NEW_ACCOUNT_ID: this repo's documented convention for a PUT-creates-account URL (see CLAUDE.md's \"Use NEW_ACCOUNT_ID for PUT-creates-account URLs\" gotcha).",
+ "lift_digest": "1c0ca8143e3e026ebd7129941384db521bac7e280dc0bcf11399e89a1575a6e5",
+ "http4s_digest": "996f7a532a9fd29d5a20500f888ca982522856316442612d4ce4087702ae1c3b"
+ },
+ {
+ "version": "v2_0_0",
+ "endpoint": "createUser",
+ "field": "errorResponseBodies",
+ "reason": "Lift's own doc self-contradicted (\"No authorisation required\", handler has no auth call, yet listed AuthenticatedUserIsRequired); http4s removed the contradictory entry.",
+ "lift_digest": "bc316dc21d8e67f81a6313e119c9a1b1d021cb7b9399429a4545cb39e57b8930",
+ "http4s_digest": "f2a1b24fe00e6ab31696e04709874f481a2b92117e4ba0d8e34e09571b1368f7"
+ },
+ {
+ "version": "v2_1_0",
+ "endpoint": "answerTransactionRequestChallenge",
+ "field": "requestUrl",
+ "reason": "Lift generates one ResourceDoc per known transaction-request type via a .foreach loop over a literal-typed list (SANDBOX_TAN/COUNTERPARTY/SEPA/FREE_FORM, all in the recognized ALL_CAPS literal set) -- the parity tool's string-only parser can't evaluate that interpolation; the actual generated URL matches http4s.",
+ "lift_digest": "93db47095d4c55c632da47a706d21a79de188a6ad808f2c570b54b1a131747b2",
+ "http4s_digest": "20c01ec634b06a02892080510d3a07026e5a2d029cdff45006a723b53aa6fa5a"
+ },
+ {
+ "version": "v2_2_0",
+ "endpoint": "createAccount",
+ "field": "requestUrl",
+ "reason": "ACCOUNT_ID -> NEW_ACCOUNT_ID, same PUT-creates-account convention as v2.0.0.",
+ "lift_digest": "1c0ca8143e3e026ebd7129941384db521bac7e280dc0bcf11399e89a1575a6e5",
+ "http4s_digest": "996f7a532a9fd29d5a20500f888ca982522856316442612d4ce4087702ae1c3b"
+ },
+ {
+ "version": "v2_2_0",
+ "endpoint": "createViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "91d541e4991471ff3b872dabd9b68fe6bc29b979fc91df495643a3bd361c0d60",
+ "http4s_digest": "69ccaef44e7ddda887462c6431f0ffe7b0f0a4a91f4e12bb5f207dffb3d3dc20"
+ },
+ {
+ "version": "v2_2_0",
+ "endpoint": "updateViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> UPD_VIEW_ID, documented bypass-variable convention for a view-update URL.",
+ "lift_digest": "7ff8ab9d5f5380b422cd7e8e46bc1a4beaa86e5eec2aea467285384a2593404a",
+ "http4s_digest": "cf5294172b6fea51500e1502a5dcb8efc1818f5c5216d0eb022e2fce18149f92"
+ },
+ {
+ "version": "v3_0_0",
+ "endpoint": "createViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "Template variable renamed for clarity; same URL path shape, same route.",
+ "lift_digest": "91d541e4991471ff3b872dabd9b68fe6bc29b979fc91df495643a3bd361c0d60",
+ "http4s_digest": "69ccaef44e7ddda887462c6431f0ffe7b0f0a4a91f4e12bb5f207dffb3d3dc20"
+ },
+ {
+ "version": "v3_0_0",
+ "endpoint": "getAtms",
+ "field": "errorResponseBodies",
+ "reason": "Dropped \"No ATMs available. License may not be set.\" -- verified even Lift's own handler only ever throws the plain atmsNotFound message, never this license-specific variant; the string was already dead in Lift.",
+ "lift_digest": "099baa28c79568b066fdbbd51ef7e3772365d9b427445e03d0e4f89b8be168c6",
+ "http4s_digest": "266858573788363b20c268a76fb993e29a82e884667ec1a8f2ec8d27a9b88700"
+ },
+ {
+ "version": "v3_0_0",
+ "endpoint": "getFirehoseAccountsAtOneBank",
+ "field": "requestUrl",
+ "reason": "BANK_ID/VIEW_ID -> FIREHOSE_BANK_ID/FIREHOSE_VIEW_ID, this repo's documented firehose-pattern bypass convention (prop check before role check before bank lookup).",
+ "lift_digest": "3cb31cd0d359a4d9cd387dcf9d99ed93d806828aaaf55a1daf682ea58fbe9d11",
+ "http4s_digest": "cff4cca2eb8ca403c84fbcd0e70a60c30e68d9d5c4499be8c75f6b3036a72166"
+ },
+ {
+ "version": "v3_0_0",
+ "endpoint": "getFirehoseTransactionsForBankAccount",
+ "field": "requestUrl",
+ "reason": "Same firehose bypass convention.",
+ "lift_digest": "9cb3633ad4dd326014aa955880c1eeacaa964d010e8603e514bbfc2925486ee0",
+ "http4s_digest": "0ef0bb4cc1bbfd07431bc2888af2111f53940ec2f13968b5aa088db8c1a60f21"
+ },
+ {
+ "version": "v3_0_0",
+ "endpoint": "updateViewForBankAccount",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> UPD_VIEW_ID convention.",
+ "lift_digest": "7ff8ab9d5f5380b422cd7e8e46bc1a4beaa86e5eec2aea467285384a2593404a",
+ "http4s_digest": "cf5294172b6fea51500e1502a5dcb8efc1818f5c5216d0eb022e2fce18149f92"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "createAccount",
+ "field": "requestUrl",
+ "reason": "ACCOUNT_ID -> NEW_ACCOUNT_ID, PUT-creates-account convention.",
+ "lift_digest": "1c0ca8143e3e026ebd7129941384db521bac7e280dc0bcf11399e89a1575a6e5",
+ "http4s_digest": "996f7a532a9fd29d5a20500f888ca982522856316442612d4ce4087702ae1c3b"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "deleteSystemView",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> SYS_VIEW_ID rename, same shape (system views have no per-account scoping).",
+ "lift_digest": "0b18308242af8b26c8ed51c3dda373102a35ddc0fc88a0512f972788cc1c410c",
+ "http4s_digest": "9a09487c0a48159914955edf656a8c22cd1b959f54216841b08dcc5bb7f56130"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "getFirehoseCustomers",
+ "field": "requestUrl",
+ "reason": "BANK_ID -> FIREHOSE_BANK_ID, firehose bypass convention.",
+ "lift_digest": "acdae6ea339535a30fc3202a587ef2400204bdde069534b12db279f23266e4fc",
+ "http4s_digest": "e4afad2ec15fdef8baa230a79ca71ff47388b2ce598fbe022c2c31518edac0ff"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "getObpConnectorLoopback",
+ "field": "description",
+ "reason": "Verified the Lift handler actually calls anonymousAccess (no auth), despite Lift's own doc wrongly claiming auth was required -- code carries an explicit fix-commit reference; http4s's doc corrects it to match real (and correct) behavior.",
+ "lift_digest": "eaae2d835b5a88d035e26697549f705d6a1d67a4cee855d3b90dbd23fde0ff01",
+ "http4s_digest": "5a0d17aff0006e43bc63109c8b6a2efaec1b4f7c832a9ab034b45c6bd1d502e4"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "getSystemView",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> SYS_VIEW_ID rename.",
+ "lift_digest": "0b18308242af8b26c8ed51c3dda373102a35ddc0fc88a0512f972788cc1c410c",
+ "http4s_digest": "9a09487c0a48159914955edf656a8c22cd1b959f54216841b08dcc5bb7f56130"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "getTransactionByIdForBankAccount",
+ "field": "description",
+ "reason": "Lift's \"optional auth\" doc wording was already inaccurate: the handler unconditionally calls authenticatedAccess (verified in the commented-out Lift source), so http4s's \"Required\" wording/error-list entry corrects a pre-existing Lift doc bug rather than changing behavior.",
+ "lift_digest": "1cd8e44d4596ded79ce9f0c90015ed4effc3893d297a0645a3c781663a607db7",
+ "http4s_digest": "af12e5dc10c9e841ac07aab24f7289abef384fa807f286eb0b2860d4c1868a94"
+ },
+ {
+ "version": "v3_1_0",
+ "endpoint": "updateSystemView",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> SYS_VIEW_ID rename.",
+ "lift_digest": "0b18308242af8b26c8ed51c3dda373102a35ddc0fc88a0512f972788cc1c410c",
+ "http4s_digest": "9a09487c0a48159914955edf656a8c22cd1b959f54216841b08dcc5bb7f56130"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "answerTransactionRequestChallenge",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> GRANT_VIEW_ID: checkAuthorisationToCreateTransactionRequest handles the view/role authorisation logic internally, matching this repo's documented bypass convention.",
+ "lift_digest": "93db47095d4c55c632da47a706d21a79de188a6ad808f2c570b54b1a131747b2",
+ "http4s_digest": "218a317170806d0f4303f5f1a91e49acbe2c6ca2a1ec43672365bb03aae1d35a"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestAccount",
+ "field": "requestUrl",
+ "reason": "Literal \"ACCOUNT\" segment generalized to a TRANSACTION_REQUEST_TYPE wildcard + GRANT_VIEW_ID: a single generic http4s handler now serves what were 9 separate per-type Lift doc aliases (confirmed by a matching code comment).",
+ "lift_digest": "f05f20b524d4f6546c826d4c69d9e40f785c624e77956c9fb0389160a03054ca",
+ "http4s_digest": "dc93a9444e21bd6540d25ed64b94db928463b2cb6468129c8dd92b8316f53886"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestAccountOtp",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same generic-handler consolidation as createTransactionRequestAccount.",
+ "lift_digest": "e77cc0608c5a2a6a7770aca934834974e7899b83bb5b4618b218840579644829",
+ "http4s_digest": "ffe3b0b3afeefb7d9ed88c9b974bb6e2c15fd98a1eb1f537cc5743bc9d98bc7d"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestAgentCashWithDrawal",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "50bc6cf2192b86d510bdec7bfd81c02d1541cddd9ddd2f50e048ce745162b1e4",
+ "http4s_digest": "1266145a5230a2e755ffd14605dd987737b457b67f76129dfc251583b9c228b6"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestCounterparty",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "a3f0c9fce8ae738505b0e20c97d3648da1fcb187a0b5f882a60caf9ebe79b9a6",
+ "http4s_digest": "d02b2af1bacce08ef5a482be184b94b216efea06c0717ceeabf2a80184798fc3"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestFreeForm",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "b075c9ace06aabc8bc5fae482b1854cc1d70eaae8300facc7e9df87a84dfc1e3",
+ "http4s_digest": "5b2c676937629c0e8abd8a742ee19b253d14d26e0e759ad6ea2e1020af5d1b74"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestRefund",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "314639471d56a3faa5c84d4ed57ede9a609d43989a5a5567f560d45a4251c310",
+ "http4s_digest": "7e792d6e14b9b951747e90f337a97d7ff32748fd36d3aa777830fff5b2548ade"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestSepa",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "8f55f7f99b1c8fa0a93af70f485ad07ce813bf8f614209649bbd39a8682e89ed",
+ "http4s_digest": "3093af72b9bb849cb55140b25e6ecfa88d63887ccd7ffaf6bbe73a76b48d6375"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "createTransactionRequestSimple",
+ "field": "requestUrl",
+ "reason": "GRANT_VIEW_ID bypass convention, same consolidation.",
+ "lift_digest": "41bc774398ad113f466233d4db2d380e476d687c0699734b046182fa8a677897",
+ "http4s_digest": "73cbb5f0f358d93b738be2acbc34f75438dae36186482f2650a5ba8dcee9c5f2"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteBankLevelDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Lift's \"DYNAMIC-RESOURCE-DOC-ID\" used hyphens, which the URL-template-variable matcher's regex (upper/underscore/digit only) can't recognize as a variable -- a genuine broken Lift template; http4s's underscore form is the fix.",
+ "lift_digest": "88d3999f8d4a15b904b69b597c770539efcee05cf149c0eb47cba88e4134bce8",
+ "http4s_digest": "ab7e41da4bb607ed2e1f5008352a6914ce993c1bb231d21e183bb53e78988da7"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteCustomerAttribute",
+ "field": "requestUrl",
+ "reason": "Lift's own documented URL didn't even match Lift's own real route pattern (verified against the actual case match); http4s's URL matches the real route on both sides.",
+ "lift_digest": "596f6923d80a84c96905e8d5136b3ac8a470d10bcb4ca657c73e3fbd5213f3f9",
+ "http4s_digest": "deed8faaba6ece8aae3ce965522969e224a3a312842acd8a144efdd496189fbd"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Same hyphen-vs-underscore template bug fix as deleteBankLevelDynamicResourceDoc.",
+ "lift_digest": "1121e061bb57d86b7b28c331cfd46382f6bc01b163301a62871d5c95b0240eab",
+ "http4s_digest": "1216685612894e081ee8c9fa73e16bec14351fa08675b4c15c7f5043a3578c03"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteExplicitCounterparty",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID -> COUNTERPARTY_ID_PARAM rename, same shape.",
+ "lift_digest": "921d75d9e3f3f8829417e01b547c83bb66305f39e6125d07641d70228ba12762",
+ "http4s_digest": "f17aeac76f848755b702722badaf8024590ced0c796cdf6467cc8f3ca0cabf2e"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteUser",
+ "field": "description",
+ "reason": "Expanded description accurately documents verified soft-delete/PII-scramble behavior (AuthUser.scrambleAuthUser, scrambleDataOfResourceUser in the real handler).",
+ "lift_digest": "f2e1d5e50e5b129805fcae2dbfe8e6fc681605ba65c67c1b734bf3f3a14a66d4",
+ "http4s_digest": "017005c0edb02ebf0b68a20c3e82936cdb06b2febe71dbd87c49799ff6396d8d"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "deleteUser",
+ "field": "errorResponseBodies",
+ "reason": "Added UserNotFoundById matches NewStyle.function.findByUserId's real 404 throw path.",
+ "lift_digest": "cb07b8a8074c71a21a64f9030e412d57858383e4f503c2444c6c7000be5f4030",
+ "http4s_digest": "a003e5f03ffb40b5f4a181a71c84a68bef06dbb387a7eacfcc268329f2bc3f63"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getApiCollectionEndpoints",
+ "field": "description",
+ "reason": "Handler uses EndpointHelpers.withUser (mandatory auth); Lift's error list already declared AuthenticatedUserIsRequired despite the doc prose saying \"optional\" -- wording-only fix.",
+ "lift_digest": "da56c88584e174c7ba38ccc3ec17ee09b8b04419ddea5c9d30dbf56f745b5405",
+ "http4s_digest": "9f052c622860ce2c8b975130944309ef48373a8d2dc20f26b5d790c6c04ab478"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getBankLevelDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Hyphen -> underscore template fix, same pattern as deleteBankLevelDynamicResourceDoc.",
+ "lift_digest": "88d3999f8d4a15b904b69b597c770539efcee05cf149c0eb47cba88e4134bce8",
+ "http4s_digest": "ab7e41da4bb607ed2e1f5008352a6914ce993c1bb231d21e183bb53e78988da7"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getCounterpartyByIdForAnyAccount",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "10cc23745c9f2e446f7128aebff01d4cd79e7390299d1ff9d53782c8e199a0c8",
+ "http4s_digest": "ca07ee2eaee48c958711ac6e697032ac41035a9fdfe4ee4cdc71ff6ea4412cb9"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Hyphen -> underscore template fix.",
+ "lift_digest": "1121e061bb57d86b7b28c331cfd46382f6bc01b163301a62871d5c95b0240eab",
+ "http4s_digest": "1216685612894e081ee8c9fa73e16bec14351fa08675b4c15c7f5043a3578c03"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getExplicitCounterpartyById",
+ "field": "requestUrl",
+ "reason": "EXPLICIT_COUNTERPARTY_ID rename.",
+ "lift_digest": "921d75d9e3f3f8829417e01b547c83bb66305f39e6125d07641d70228ba12762",
+ "http4s_digest": "51b5c4487bf594005cbd5895f0fa7f8f2ef4ed246386e9cd2fb154c386d5289b"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getFirehoseAccountsAtOneBank",
+ "field": "requestUrl",
+ "reason": "FIREHOSE_* bypass convention.",
+ "lift_digest": "3cb31cd0d359a4d9cd387dcf9d99ed93d806828aaaf55a1daf682ea58fbe9d11",
+ "http4s_digest": "cff4cca2eb8ca403c84fbcd0e70a60c30e68d9d5c4499be8c75f6b3036a72166"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "getMyApiCollectionEndpoint",
+ "field": "description",
+ "reason": "Same withUser-mandatory-auth wording fix as getApiCollectionEndpoints.",
+ "lift_digest": "8237405b9168c43679498d41aab3e252520db73a10e161ba9b00cde41c183fda",
+ "http4s_digest": "3ed2f6d19d0896daf0ede47fbd5183192052f4ef0354140c3c8320ea420e2c96"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "updateBankLevelDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Hyphen -> underscore template fix.",
+ "lift_digest": "88d3999f8d4a15b904b69b597c770539efcee05cf149c0eb47cba88e4134bce8",
+ "http4s_digest": "ab7e41da4bb607ed2e1f5008352a6914ce993c1bb231d21e183bb53e78988da7"
+ },
+ {
+ "version": "v4_0_0",
+ "endpoint": "updateDynamicResourceDoc",
+ "field": "requestUrl",
+ "reason": "Hyphen -> underscore template fix.",
+ "lift_digest": "1121e061bb57d86b7b28c331cfd46382f6bc01b163301a62871d5c95b0240eab",
+ "http4s_digest": "1216685612894e081ee8c9fa73e16bec14351fa08675b4c15c7f5043a3578c03"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "createAccount",
+ "field": "requestUrl",
+ "reason": "ACCOUNT_ID -> NEW_ACCOUNT_ID, PUT-creates-account convention.",
+ "lift_digest": "1c0ca8143e3e026ebd7129941384db521bac7e280dc0bcf11399e89a1575a6e5",
+ "http4s_digest": "996f7a532a9fd29d5a20500f888ca982522856316442612d4ce4087702ae1c3b"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "createConsentByConsentRequestIdEmail",
+ "field": "errorResponseBodies",
+ "reason": "The compared text differs only because one side references a shared error-list val the parity tool's string-only parser can't expand; the expanded error sets are identical between Lift and http4s.",
+ "lift_digest": "73f681411b6caa8d703781d5e2ffa8d4adc252fe915861d9620d52ba70157489",
+ "http4s_digest": "4e326ecc2fd12e943dbc15696a9619302b28d7c6b7405f61807855d3c538b979"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "createConsentByConsentRequestIdImplicit",
+ "field": "errorResponseBodies",
+ "reason": "Same shared-val expansion artifact as createConsentByConsentRequestIdEmail; expanded sets are identical.",
+ "lift_digest": "1cb5a60be98c8388253c1855e0b351469e254c5dee7ab2f42d388fe6c213da14",
+ "http4s_digest": "7affd9a379cb014033cdab59e2f4c7df80fbcb89ee3b14b126ae3fc11f20747f"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "createConsentByConsentRequestIdSms",
+ "field": "errorResponseBodies",
+ "reason": "Same shared-val expansion artifact; expanded sets are identical.",
+ "lift_digest": "1cb5a60be98c8388253c1855e0b351469e254c5dee7ab2f42d388fe6c213da14",
+ "http4s_digest": "7affd9a379cb014033cdab59e2f4c7df80fbcb89ee3b14b126ae3fc11f20747f"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "createSystemView",
+ "field": "errorResponseBodies",
+ "reason": "Lift's own handler already calls booleanToFuture(SystemViewCannotBePublicError) and booleanToFuture(InvalidSystemViewFormat), but Lift's doc never listed either; http4s's doc now matches Lift's actual (previously undocumented) behavior.",
+ "lift_digest": "8b9e9294a47baff632975336cec3da4c29f3ca3b8398ec5875e9b5d1712f0140",
+ "http4s_digest": "86b918e0ba878c05794b6c96846058bb96884bac0750b422ba186cf57d2fbde7"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "deleteSystemView",
+ "field": "errorResponseBodies",
+ "reason": "System views are global (no per-account scoping) and Lift's handler does no bank/account lookup or owner-check; \"BankAccountNotFound\"/owner-access errors were stale copy-paste from the per-account view doc. SystemViewNotFound is the accurate error.",
+ "lift_digest": "3cbdd13dcb3b9c6dbb79a6002c7327fe8e948e54c347632b8f6cf7007354f726",
+ "http4s_digest": "972bae654c5326034add61dfd146950777ee0dbca6520278a267fd90bba0ef1f"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "getSystemView",
+ "field": "errorResponseBodies",
+ "reason": "Lift's handler (ViewNewStyle.systemView) does no bank lookup at all -- BankNotFound was never reachable/stale. SystemViewNotFound is accurate.",
+ "lift_digest": "8ffb72b0f6f2bd94179e19b1bd970a051ad05b0f6bf0050671b0e87026f74da4",
+ "http4s_digest": "972bae654c5326034add61dfd146950777ee0dbca6520278a267fd90bba0ef1f"
+ },
+ {
+ "version": "v5_0_0",
+ "endpoint": "updateSystemView",
+ "field": "errorResponseBodies",
+ "reason": "Same as deleteSystemView, plus SystemViewCannotBePublicError added to match a check present in Lift's own handler but missing from Lift's doc.",
+ "lift_digest": "b79eb9fab21789a0fdc429074f4eb69cb0a23e86d7473d8baed55c7d54ec96df",
+ "http4s_digest": "9ebff8506d69c4ce6383902d5d832f903e4b0a3a9a1298917c919a418ffaf349"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "backupBankLevelDynamicEntity",
+ "field": "description",
+ "reason": "Markdown fix: literal (renders as broken/stripped HTML) -> {BackupEntityName}.",
+ "lift_digest": "de00efcfa1254232a9f5790b53695dc09e402ac41ed964097ffff58d132c7839",
+ "http4s_digest": "841d99862cc813c235593fc43d722692084dfca390ccc07c2c0dc054ded772a2"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "backupSystemDynamicEntity",
+ "field": "description",
+ "reason": "Same markdown fix as backupBankLevelDynamicEntity.",
+ "lift_digest": "172ecd180e7c87fd9080d231736f8ea1e5d130fdc9224adb017d69494edba066",
+ "http4s_digest": "5f61128bd66efed0f37498698f7819d75cc2dcbb4501d09e96fd74769eeb4c55"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createBankLevelDynamicEntity",
+ "field": "description",
+ "reason": "Documents real, verified new fields (indexed/index, write_role_required/read_role_required/write_role/read_role) present in DynamicEntityProvider.scala/DynamicEntityHelper.scala.",
+ "lift_digest": "2e7c649041362776f7eec66ccbb9f025f3edfead992108d0fd5864af76e93961",
+ "http4s_digest": "012d3dac115f98f7cc0dd068b4a19ea71cec2b0baace4fbe8699c8a0c1c66286"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createCounterpartyAttribute",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "4afc1baca0551e1cb89611a42c0d7652e3040468728f465d9061052414e6e1a9",
+ "http4s_digest": "5f2aedc26f7688fd913b6f9dffe12c6858fb3814c7515530861a1613afb8a5b5"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createPersonalDataField",
+ "field": "description",
+ "reason": "Additive clarification (USER_ATTRIBUTE_ID identity, non-unique name, PUT-to-update guidance); nothing removed.",
+ "lift_digest": "4cc47e93f3737a605729f4aaf7b439d5ee8e99b737185fe1239487b30980d412",
+ "http4s_digest": "ae08eb6afbbace39d0834e20610b06ac5d4e50422f84dad91c471a3370267788"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createSystemDynamicEntity",
+ "field": "description",
+ "reason": "Same real-feature doc addition as createBankLevelDynamicEntity.",
+ "lift_digest": "81310cdd2be1c2b33d465cabd1604cedee38bfa1ecccae4b016d0f99aa443ab6",
+ "http4s_digest": "c1e0aa2666de3b04a979bb6ffa669b3767317a3cf5d386c1dcc6a89526aa1f9a"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createTransactionRequestCardano",
+ "field": "requestUrl",
+ "reason": "Verified Lift's own real route already captures a generic ViewId(viewId) -- Lift's doc hardcoding the literal \"owner\" was already inaccurate; http4s's VIEW_ID reflects the real route.",
+ "lift_digest": "ff4ed15c0eaf5e7e2220254098f7cf17ce2a19d0134205675a0db48f8992c396",
+ "http4s_digest": "62ff5fec9efa48f21dc32d5f95fd9f23d8eecf6d94ad047bb81464748b4047c2"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "createTransactionRequestHold",
+ "field": "requestUrl",
+ "reason": "Same real-route verification as createTransactionRequestCardano.",
+ "lift_digest": "f171234e229c0a8c5636773ff0eef555a86cc86cbce6dd89854d72157d56c76a",
+ "http4s_digest": "4f6ba60ae9bfce501646d1311bfb1d544d3ecbf02b4b5e522e8da293d3407c04"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "deleteCounterpartyAttribute",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "6be19ba2409dbba4ae9f6ed783f5a2068645dd189761c83af8cd0d9f107a22f4",
+ "http4s_digest": "2cb204a9cd0b15471f6fdbe274209d3f4cce2a4d016f0fd8526b0b24fa640d8a"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "deletePersonalDataField",
+ "field": "description",
+ "reason": "Additive clarification, same pattern as createPersonalDataField.",
+ "lift_digest": "eb5db36d3a298202c0a5f1d2ef27caf84107946fa4a0a3712b334e8039285f59",
+ "http4s_digest": "c7d6e21871a9248a21ab00a16518158d065ba56348343324b92043604c7b6e0c"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "deleteSignalChannel",
+ "field": "description",
+ "reason": "Verified, deliberate security fix: a CanDeleteSignalChannel role gate was genuinely added post-migration (previously any authenticated user could destroy any channel, including another user's in-flight messages) -- documented in a matching code comment.",
+ "lift_digest": "917926fcd80c03907fa711563a9a14e93ebcb58164ae4d28b869226a1bd4795b",
+ "http4s_digest": "59f207ff74781112cf7d6f795dc62b6824c06e7dd8b85495e9704ac78f60bc47"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "deleteSignalChannel",
+ "field": "errorResponseBodies",
+ "reason": "UserHasMissingRoles addition matches the real new role gate (ResourceDoc declares Some(canDeleteSignalChannel :: Nil)).",
+ "lift_digest": "a83dad7a55122752ac89cc9f7e9b5fbcbba8692801ad864d6e1aebcfd2dfa9f4",
+ "http4s_digest": "6605e62014a3fc89bda9d1b256974c9dfaba58289dc0d461f832cd5af575e843"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAggregateMetrics",
+ "field": "description",
+ "reason": "Documents real new response fields (distinct_user_count etc.) verified present in MappedMetrics.scala.",
+ "lift_digest": "21e12b117560d354f2ee58bb845e9a5d39d9f47721da8195868cf7a6ed9a216d",
+ "http4s_digest": "7e83ca3e1b2c02edfe20ecd786d397abb899fe37bc5bf42028fb03734cb627cd"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAllApiProductsV600",
+ "field": "description",
+ "reason": "Verified handler uses EndpointHelpers.withUser (mandatory auth) unconditionally; \"Required\" is accurate -- the conditional getApiProductsIsPublic flag governs a different sibling endpoint, not this one.",
+ "lift_digest": "9940ac8e6f7dbf5a4e4e5d8a65635722e8ce8839f7954ad39f99c1eee3f12865",
+ "http4s_digest": "b8f6c80d7d9aab5c1954d93d78e4e9caaf55bbba86cedc57b614c7350f5d8fda"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAllCounterpartyAttributes",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "4afc1baca0551e1cb89611a42c0d7652e3040468728f465d9061052414e6e1a9",
+ "http4s_digest": "5f2aedc26f7688fd913b6f9dffe12c6858fb3814c7515530861a1613afb8a5b5"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAllProductsV600",
+ "field": "description",
+ "reason": "Same withUser-mandatory-auth verification as getAllApiProductsV600.",
+ "lift_digest": "95a38b38425c735bb39869aa81cf43011fd62525ce53a1f78b40b3fe6eec69df",
+ "http4s_digest": "11fdd7cf9a24c1a824bd01884b06c118332ca5219720b8bf76a5d177fb500800"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getAppDirectory",
+ "field": "description",
+ "reason": "Additive clarification, nothing removed.",
+ "lift_digest": "d92aec65916179b76ddfe8cc8040465ac06c69dff9fea5a0ed7aea28c0f926a3",
+ "http4s_digest": "16f6e6359454b25aeca6f6dd13945d5987010cce18385360cfed9308037d3e22"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getConfigProps",
+ "field": "description",
+ "reason": "Plain-text \"Authentication is Required.\" reworded to an interpolated form with identical meaning.",
+ "lift_digest": "a4886b5dc349fd22cec6ffc735bd9fb47f5637a426c6365640cf5e486d81e8ef",
+ "http4s_digest": "a4f95be6ce6e6f5e56619c0d756f60f701d9f8edfb88adc03fff38ed790eb364"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getConnectorTraces",
+ "field": "description",
+ "reason": "Same wording normalization as getConfigProps.",
+ "lift_digest": "f41cdd1dbacdfd52a114a2dc76487367b4b20746184d32d3b0709bd858b8363d",
+ "http4s_digest": "835e4890e3775490f00f47ca65a16e63acc63d6cf1961976712b585b643e54e2"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getCounterpartyAttributeById",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "6be19ba2409dbba4ae9f6ed783f5a2068645dd189761c83af8cd0d9f107a22f4",
+ "http4s_digest": "2cb204a9cd0b15471f6fdbe274209d3f4cce2a4d016f0fd8526b0b24fa640d8a"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getMetrics",
+ "field": "description",
+ "reason": "Documents real new filter params (consent_reference_id, certificate_trust) verified present in MappedMetrics.scala.",
+ "lift_digest": "04c081020abb8a0f0bfe1b9a850c30151dac9a1cd69f4ea1cbb896388b4237f2",
+ "http4s_digest": "3e6c35656f1605ba23ae225187a4038f9f4ae48195824e5f4166840c325ec81a"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getPersonalDataFieldById",
+ "field": "description",
+ "reason": "Additive clarification.",
+ "lift_digest": "290b6ad436ac0625f810898115e248aef2bc9d8814ef659809e27419cb63d5cf",
+ "http4s_digest": "2e3f2ce3c000cbccff0a3b96948b66e08712a5158877a2e54ef69673cead249d"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getPersonalDataFields",
+ "field": "description",
+ "reason": "Additive clarification.",
+ "lift_digest": "9e55700ce5e99e758f29e91cb5bf6b2939bad37d02f2f6f282de1abfba3de90f",
+ "http4s_digest": "d0ffb88559c1a7e37d340f7667b9a7da1d37ed833c7330a031a28c58fb96af85"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getSystemViewById",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> SYS_VIEW_ID rename.",
+ "lift_digest": "0041a7317dbcf01050bd9bedab8ab4ed75743b5841291cf748d3ec332e2be432",
+ "http4s_digest": "f6d3e0bc564c56c7e746900443347a83592bc0eb586d0e4293ab62eccb8726e5"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "getUserGroupMemberships",
+ "field": "description",
+ "reason": "Deliberate, reasoned simplification (documented in a matching code comment): filtering by group_id alone is functionally equivalent to the old group_id + process==\"GROUP_MEMBERSHIP\" conjunct, since group_id is only ever set for that process.",
+ "lift_digest": "00695d674cb901c588ec78f9a5c33e065363fa0a5ea55ae23bde960ac464aec4",
+ "http4s_digest": "cd76da70acd6a5991f43506b12bbdd5c4c07416e092afe8ff293c0d1ed1a889c"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "publishSignalMessage",
+ "field": "description",
+ "reason": "Documents real new validation (maxPayloadLength, dangerous-character rejection) verified in SignalContentPolicy.scala/ErrorMessages.scala.",
+ "lift_digest": "5ee1e8d3e9a6d9addd3df03feda6a334c1ec4ce29bb23d60b9bbb476e476668c",
+ "http4s_digest": "53f2730fe6b58ed7efc2bffaf0f4add0f877277efbb891167f3f7c9c8d1629e3"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "publishSignalMessage",
+ "field": "errorResponseBodies",
+ "reason": "SignalMessageTooLong/SignalMessageContainsDangerousCharacters are real error constants (OBP-39019/39020) added as part of the same security-hardening change as the description update.",
+ "lift_digest": "d5760e39031ad664c98048b6474337b031c016d1de1e9a7181a5681696688f51",
+ "http4s_digest": "14bbd867d2ae350be174e3b4f07a2cda9a2213196855f8bfc766dbbbbf3811d0"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "removeBankReaction",
+ "field": "requestUrl",
+ "reason": "EMOJI -> EMOJI_REACTION rename.",
+ "lift_digest": "39346f6586aefc697ac096a6bd598f12899890d32e788d9f15d4c54584f3ccdb",
+ "http4s_digest": "f59d4a76a03f8fd5f4367e2231b8c4496fbbd1eff06755f7f5a25396e1c0bb77"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "removeSystemReaction",
+ "field": "requestUrl",
+ "reason": "EMOJI -> EMOJI_REACTION rename.",
+ "lift_digest": "9f48c024ba049e62a14e2ec97c2aede0bbcdd952047dc5ab5a1cfa01f95c6c06",
+ "http4s_digest": "7da8a4231ed6d8738a9bce3e56608f05e6947c97c11ef8dd2e7c27c983b67991"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "removeUserFromGroup",
+ "field": "description",
+ "reason": "Same deliberate group_id-only simplification as getUserGroupMemberships, verified via the same matching code comment.",
+ "lift_digest": "7ed803789f6d7fb0ee0622523f4e3835ab7cbc166efd9c2454882836224db13f",
+ "http4s_digest": "9e2a740a07e70eb3bdd0b54afe2406fa70aab3a7941fa88d02970657d5f8ee21"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "resetPasswordUrl",
+ "field": "description",
+ "reason": "Verified the handler genuinely no longer returns the reset URL in the response body (only {\"status\":\"sent\",\"to\":email}) -- a documented, reasoned security fix closing an account-takeover vector (see also the successResponseBody allowlist entry for this same endpoint).",
+ "lift_digest": "dca0922381fb4c5f1fb34ab5a531d440b068f2170fd933c3c2eeddb4c52eaf94",
+ "http4s_digest": "f0bea922b31c331bae138d58990bf31a6bc5ca0099055f4cff4fdaf62c0a6263"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateBankLevelDynamicEntity",
+ "field": "description",
+ "reason": "Real field-level-access-control feature doc addition, same pattern as createBankLevelDynamicEntity.",
+ "lift_digest": "2d18665f9db52506a1b043ad7575b16ac52cedf0d11f036afd4a96b353eb8ddd",
+ "http4s_digest": "dbd05ceaae5129f8ff61655a0007b2d715f5ef45eb7fcaf7e6261fd3a47e08a6"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateCounterpartyAttribute",
+ "field": "requestUrl",
+ "reason": "COUNTERPARTY_ID_PARAM rename.",
+ "lift_digest": "6be19ba2409dbba4ae9f6ed783f5a2068645dd189761c83af8cd0d9f107a22f4",
+ "http4s_digest": "2cb204a9cd0b15471f6fdbe274209d3f4cce2a4d016f0fd8526b0b24fa640d8a"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateMyDynamicEntity",
+ "field": "description",
+ "reason": "Real feature doc addition, same pattern as createBankLevelDynamicEntity.",
+ "lift_digest": "97f0c97cc592f89f4dba8a6641ad4b41f6ffa6f4f6e78bf3d3cc34a6a11f76e7",
+ "http4s_digest": "c9c75c8112aea6fd914b131e0b81a79b149d4885c82d272016259af40f8207d4"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updatePersonalDataField",
+ "field": "description",
+ "reason": "Additive clarification.",
+ "lift_digest": "b2a8abcba137c01ec9e67c4c58eb5d7c6596508a12219f87092c5773c29916b3",
+ "http4s_digest": "85090153d93338f56d26c549900bdba3c2467269c740ef4f9752c7ad88d806dc"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateSystemDynamicEntity",
+ "field": "description",
+ "reason": "Real feature doc addition, same pattern as createBankLevelDynamicEntity.",
+ "lift_digest": "e28c2996f3fd54842534fd54d45d7ba49df8b346e65f541353be4fb5311b550c",
+ "http4s_digest": "0e2017ebada85365b83b8d0fd9a3d14ce992e58276fe0a8770f04a8b7cac0b42"
+ },
+ {
+ "version": "v6_0_0",
+ "endpoint": "updateSystemView",
+ "field": "requestUrl",
+ "reason": "VIEW_ID -> UPD_VIEW_ID convention.",
+ "lift_digest": "0b18308242af8b26c8ed51c3dda373102a35ddc0fc88a0512f972788cc1c410c",
+ "http4s_digest": "dad3bc411251667d1a364b7fd8e45c54de3ef9d4d3d54f52e90e6264d53a948d"
+ }
+ ]
+}
diff --git a/scripts/restore_resource_doc_bodies.py b/scripts/restore_resource_doc_bodies.py
index e7d3df6235..24e4f98f9d 100644
--- a/scripts/restore_resource_doc_bodies.py
+++ b/scripts/restore_resource_doc_bodies.py
@@ -9,8 +9,12 @@
- errorResponseBodies
- tags
-Reads the commented Lift ResourceDocs in APIMethodsXYZ.scala and overwrites
-the matching field in Http4sXYZ.scala. Endpoints are matched by `nameOf(...)`.
+Reads the Lift-era predecessor data from the JSON baseline at
+scripts/resource_doc_baseline/lift_resource_docs_vX_Y_Z.json (see that
+directory's README) — originally commented-out ResourceDocs in
+APIMethodsXYZ.scala, now JSON since those .scala files were deleted once the
+baseline was verified to reproduce them losslessly — and overwrites the
+matching field in Http4sXYZ.scala. Endpoints are matched by `nameOf(...)`.
Usage:
python3 scripts/restore_resource_doc_bodies.py v6_0_0
@@ -18,7 +22,7 @@
python3 scripts/restore_resource_doc_bodies.py v6_0_0 --fields=tags
python3 scripts/restore_resource_doc_bodies.py v6_0_0 --only=getXyz
-Read+writes the http4s file in place. Does NOT touch the Lift file.
+Read+writes the http4s file in place. Does NOT touch the JSON baseline.
"""
import argparse
@@ -30,28 +34,20 @@
REPO_ROOT = Path(__file__).resolve().parents[1]
API_ROOT = REPO_ROOT / "obp-api" / "src" / "main" / "scala" / "code" / "api"
-POSITIONAL_FIELDS = [
- "partialFunction", # 0
- "implementedInApiVersion", # 1
- "partialFunctionName", # 2 — endpoint identifier (nameOf(...))
- "requestVerb", # 3
- "requestUrl", # 4
- "summary", # 5
- "description", # 6
- "exampleRequestBody", # 7
- "successResponseBody", # 8
- "errorResponseBodies", # 9
- "tags", # 10
-]
-
-NAMED_ARG_FIELDS = {
- "roles",
- "http4sPartialFunction",
- "isFeatured",
- "specialInstructions",
- "createdByBankId",
- "authMode",
-}
+SCRIPT_DIR = Path(__file__).resolve().parent
+sys.path.insert(0, str(SCRIPT_DIR))
+import check_lift_http4s_resource_doc_parity as parity # noqa: E402
+
+# Kept as the canonical field-name list for --fields validation and iteration —
+# both ResourceDoc constructor signatures (pre- and post-Lift-teardown) share
+# these same field NAMES, just at different positional indices. See
+# detect_fields() below for the index-detection logic, reused from
+# check_lift_http4s_resource_doc_parity.py's own POSITIONAL_FIELDS /
+# CURRENT_POSITIONAL_FIELDS split (the same split this file used to duplicate
+# with a single hardcoded — and pre-teardown-only — index list, which had
+# silently stopped matching any current Http4sXYZ.scala file).
+POSITIONAL_FIELDS = parity.POSITIONAL_FIELDS
+NAMED_ARG_FIELDS = parity.NAMED_ARG_FIELDS
DEFAULT_FIELDS_TO_RESTORE = [
"summary",
@@ -60,17 +56,6 @@
]
-def uncomment(source: str) -> str:
- out = []
- for line in source.splitlines():
- m = re.match(r"^(\s*)//\s?(.*)$", line)
- if m:
- out.append(m.group(1) + m.group(2))
- else:
- out.append(line)
- return "\n".join(out)
-
-
def _skip_string_or_comment(source: str, i: int):
n = len(source)
c = source[i]
@@ -203,68 +188,41 @@ def parse_args(body: str):
return positional, named
-def endpoint_name(part_fn_name: str) -> str:
- """Like in check_lift_http4s_resource_doc_parity.py: also evaluate
- chained `.replace("a", "b")` calls so derived names match."""
- s = (part_fn_name or "").strip()
- rest = s
- m = re.match(r"^nameOf\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)", s)
- if m:
- base = m.group(1)
- rest = s[m.end():]
- elif s.startswith('"'):
- m2 = re.match(r'^"([^"]*)"', s)
- if not m2:
- return s
- base = m2.group(1)
- rest = s[m2.end():]
- else:
- return s
- rep_re = re.compile(r'^\s*\.\s*replace\s*\(\s*"([^"]*)"\s*,\s*"([^"]*)"\s*\)')
- while True:
- m = rep_re.match(rest)
- if not m:
- break
- base = base.replace(m.group(1), m.group(2))
- rest = rest[m.end():]
- return base
-
-
-def find_pair_for_version(version_dir: Path):
- api_methods = list(version_dir.glob("APIMethods*.scala"))
- http4s = list(version_dir.glob("Http4s*.scala"))
- if not api_methods or not http4s:
- return None
- def pick(files, prefix):
- ranked = sorted(
- files,
- key=lambda p: (
- 0 if re.match(rf"^{prefix}\d+\.scala$", p.name) else 1,
- len(p.name),
- ),
+def detect_fields(positional):
+ """Return the field-name list matching THIS particular call's constructor
+ signature, or None when neither shape is recognisable.
+
+ Pre-teardown calls carry a leading `partialFunction` (verb literal at index
+ 3); current ones do not (verb literal at index 2). The verb literal is the
+ discriminator, so exactly one of those two positions must hold one —
+ neither, or both, means this is not a shape the tool understands.
+
+ None is returned rather than defaulting to either layout because the caller
+ rewrites the file: guessing wrong shifts every field by one and would write
+ a field's text into its neighbour's slot. Reuses
+ check_lift_http4s_resource_doc_parity.py's own constants instead of a second
+ hardcoded guess — this file's old fixed index-2 name lookup had silently
+ stopped matching any current-signature Http4sXYZ.scala file.
+ """
+ def verb_at(i):
+ return len(positional) > i and positional[i]["text"].strip() in parity.HTTP_VERB_LITERALS
+
+ current, legacy = verb_at(2), verb_at(3)
+ if current and not legacy:
+ return parity.CURRENT_POSITIONAL_FIELDS
+ if legacy and not current:
+ return parity.POSITIONAL_FIELDS
+ return None
+
+
+def collect_lift_docs(version: str):
+ """Return {endpoint_name -> {field_name -> raw_text}} from the JSON baseline."""
+ docs = parity.load_baseline_docs(version)
+ if docs is None:
+ raise FileNotFoundError(
+ f"no baseline at {parity.BASELINE_DIR / f'lift_resource_docs_{version}.json'} "
+ f"— see scripts/resource_doc_baseline/README.md"
)
- return ranked[0]
- return pick(api_methods, "APIMethods"), pick(http4s, "Http4s")
-
-
-def collect_lift_docs(path: Path):
- """Return {endpoint_name -> {field_name -> raw_text}}."""
- source = path.read_text(encoding="utf-8")
- active = re.search(r"^\s*(?:static)?[rR]esourceDocs\s*\+=\s*ResourceDoc\s*\(", source, re.M)
- commented = re.search(r"^\s*//\s*(?:static)?[rR]esourceDocs\s*\+=\s*ResourceDoc\s*\(", source, re.M)
- if not active and commented:
- source = uncomment(source)
- docs = OrderedDict()
- for _, _, _, body in find_resourcedoc_blocks(source):
- positional, _ = parse_args(body)
- if len(positional) < 3:
- continue
- name = endpoint_name(positional[2]["text"])
- field_values = OrderedDict()
- for idx, fname in enumerate(POSITIONAL_FIELDS):
- if idx < len(positional):
- field_values[fname] = positional[idx]["text"]
- docs.setdefault(name, field_values)
return docs
@@ -371,6 +329,7 @@ def process_file(http4s_path: Path, lift_docs: dict, dry_run: bool,
edits = []
matched = 0
skipped_no_lift = 0
+ unknown_signature = 0
changed_endpoints = 0
per_field_changes = {f: 0 for f in fields_to_restore}
@@ -378,7 +337,23 @@ def process_file(http4s_path: Path, lift_docs: dict, dry_run: bool,
positional, _ = parse_args(body)
if len(positional) < 3:
continue
- name = endpoint_name(positional[2]["text"])
+ fields = detect_fields(positional)
+ if fields is None:
+ # Never guess at an unclassifiable signature — writing to guessed
+ # offsets would move each field's text into its neighbour's slot.
+ unknown_signature += 1
+ line_no = source.count("\n", 0, header_start) + 1
+ print(
+ f" WARN: unrecognised ResourceDoc signature at "
+ f"{http4s_path.name}:{line_no} — no verb literal at positional "
+ f"index 2 or 3; skipped",
+ file=sys.stderr,
+ )
+ continue
+ name_idx = fields.index("partialFunctionName")
+ if name_idx >= len(positional):
+ continue
+ name = parity.endpoint_name(positional[name_idx]["text"])
if only_names and name not in only_names:
continue
lift = lift_docs.get(name)
@@ -392,7 +367,7 @@ def process_file(http4s_path: Path, lift_docs: dict, dry_run: bool,
# (Field indent only matters when the new value has embedded newlines.)
endpoint_changed = False
for fname in fields_to_restore:
- idx = POSITIONAL_FIELDS.index(fname)
+ idx = fields.index(fname)
if idx >= len(positional):
continue
if fname not in lift:
@@ -433,7 +408,8 @@ def process_file(http4s_path: Path, lift_docs: dict, dry_run: bool,
prefix = "[dry-run] " if dry_run else ""
print(f" {prefix}endpoints matched: {matched} changed: {changed_endpoints} "
- f"skipped (no lift match): {skipped_no_lift}")
+ f"skipped (no lift match): {skipped_no_lift} "
+ f"skipped (unrecognised signature): {unknown_signature}")
for f in fields_to_restore:
print(f" {f}: {per_field_changes[f]} fields rewritten")
@@ -441,6 +417,8 @@ def process_file(http4s_path: Path, lift_docs: dict, dry_run: bool,
http4s_path.write_text(new_source, encoding="utf-8")
print(f" wrote {http4s_path}")
+ return unknown_signature
+
def main():
ap = argparse.ArgumentParser(description=__doc__,
@@ -462,25 +440,33 @@ def main():
print(f"ERROR: unknown fields: {invalid}", file=sys.stderr)
sys.exit(2)
+ unrecognised = 0
for v in args.versions:
- version_dir = API_ROOT / v
- if not version_dir.is_dir():
- print(f"[skip] {v}: no such directory under {API_ROOT}",
+ http4s_path = parity.find_http4s_path(v)
+ if http4s_path is None:
+ print(f"[skip] {v}: no Http4s*.scala found under {API_ROOT / v}",
file=sys.stderr)
continue
- pair = find_pair_for_version(version_dir)
- if not pair:
- print(f"[skip] {v}: no APIMethods+Http4s pair found",
- file=sys.stderr)
+ try:
+ lift_docs = collect_lift_docs(v)
+ except FileNotFoundError as e:
+ print(f"[skip] {v}: {e}", file=sys.stderr)
continue
- lift_path, http4s_path = pair
print(f"\n=== {v} ===")
- print(f" lift: {lift_path.relative_to(REPO_ROOT)}")
+ print(f" lift: scripts/resource_doc_baseline/lift_resource_docs_{v}.json")
print(f" http4s: {http4s_path.relative_to(REPO_ROOT)}")
print(f" fields: {fields_to_restore}")
- lift_docs = collect_lift_docs(lift_path)
- process_file(http4s_path, lift_docs, args.dry_run,
- fields_to_restore, set(args.only) if args.only else None)
+ unrecognised += process_file(
+ http4s_path, lift_docs, args.dry_run,
+ fields_to_restore, set(args.only) if args.only else None)
+
+ # Non-zero when any registration could not be classified: the tool's
+ # assumption about the constructor shape no longer holds everywhere, and
+ # quietly patching the rest would hide that.
+ if unrecognised:
+ print(f"\nERROR: {unrecognised} ResourceDoc registration(s) had an "
+ f"unrecognised constructor signature and were skipped.", file=sys.stderr)
+ sys.exit(1)
if __name__ == "__main__":