mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(events): allow listing webhook events and webhook delivery attempts by business profile (#4159)
This commit is contained in:
@ -132,14 +132,28 @@ pub struct OutgoingWebhookResponseContent {
|
|||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
#[derive(Debug, serde::Serialize)]
|
||||||
pub struct EventListRequestInternal {
|
pub struct EventListRequestInternal {
|
||||||
pub merchant_id: String,
|
pub merchant_id_or_profile_id: String,
|
||||||
pub constraints: EventListConstraints,
|
pub constraints: EventListConstraints,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl common_utils::events::ApiEventMetric for EventListRequestInternal {
|
impl common_utils::events::ApiEventMetric for EventListRequestInternal {
|
||||||
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
|
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
|
||||||
Some(common_utils::events::ApiEventsType::Events {
|
Some(common_utils::events::ApiEventsType::Events {
|
||||||
merchant_id: self.merchant_id.clone(),
|
merchant_id_or_profile_id: self.merchant_id_or_profile_id.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct WebhookDeliveryAttemptListRequestInternal {
|
||||||
|
pub merchant_id_or_profile_id: String,
|
||||||
|
pub initial_attempt_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl common_utils::events::ApiEventMetric for WebhookDeliveryAttemptListRequestInternal {
|
||||||
|
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
|
||||||
|
Some(common_utils::events::ApiEventsType::Events {
|
||||||
|
merchant_id_or_profile_id: self.merchant_id_or_profile_id.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ pub enum ApiEventsType {
|
|||||||
dispute_id: String,
|
dispute_id: String,
|
||||||
},
|
},
|
||||||
Events {
|
Events {
|
||||||
merchant_id: String,
|
merchant_id_or_profile_id: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
/// Events - List
|
/// Events - List
|
||||||
///
|
///
|
||||||
/// List all Events associated with a Merchant Account.
|
/// List all Events associated with a Merchant Account or Business Profile.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
path = "/events/{merchant_id}",
|
path = "/events/{merchant_id_or_profile_id}",
|
||||||
params(
|
params(
|
||||||
(
|
(
|
||||||
"merchant_id" = String,
|
"merchant_id_or_profile_id" = String,
|
||||||
Path,
|
Path,
|
||||||
description = "The unique identifier for the Merchant Account"
|
description = "The unique identifier for the Merchant Account or Business Profile"
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"created_after" = Option<PrimitiveDateTime>,
|
"created_after" = Option<PrimitiveDateTime>,
|
||||||
@ -45,7 +45,7 @@
|
|||||||
(status = 200, description = "List of Events retrieved successfully", body = Vec<EventListItemResponse>),
|
(status = 200, description = "List of Events retrieved successfully", body = Vec<EventListItemResponse>),
|
||||||
),
|
),
|
||||||
tag = "Event",
|
tag = "Event",
|
||||||
operation_id = "List all Events associated with a Merchant Account",
|
operation_id = "List all Events associated with a Merchant Account or Business Profile",
|
||||||
security(("admin_api_key" = []))
|
security(("admin_api_key" = []))
|
||||||
)]
|
)]
|
||||||
pub fn list_initial_webhook_delivery_attempts() {}
|
pub fn list_initial_webhook_delivery_attempts() {}
|
||||||
@ -55,9 +55,9 @@ pub fn list_initial_webhook_delivery_attempts() {}
|
|||||||
/// List all delivery attempts for the specified Event.
|
/// List all delivery attempts for the specified Event.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
path = "/events/{merchant_id}/{event_id}/attempts",
|
path = "/events/{merchant_id_or_profile_id}/{event_id}/attempts",
|
||||||
params(
|
params(
|
||||||
("merchant_id" = String, Path, description = "The unique identifier for the Merchant Account"),
|
("merchant_id_or_profile_id" = String, Path, description = "The unique identifier for the Merchant Account or Business Profile"),
|
||||||
("event_id" = String, Path, description = "The unique identifier for the Event"),
|
("event_id" = String, Path, description = "The unique identifier for the Event"),
|
||||||
),
|
),
|
||||||
responses(
|
responses(
|
||||||
|
|||||||
@ -5,15 +5,21 @@ use crate::{
|
|||||||
core::errors::{self, RouterResponse, StorageErrorExt},
|
core::errors::{self, RouterResponse, StorageErrorExt},
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
services::ApplicationResponse,
|
services::ApplicationResponse,
|
||||||
types::{api, transformers::ForeignTryFrom},
|
types::{api, domain, transformers::ForeignTryFrom},
|
||||||
};
|
};
|
||||||
|
|
||||||
const INITIAL_DELIVERY_ATTEMPTS_LIST_MAX_LIMIT: i64 = 100;
|
const INITIAL_DELIVERY_ATTEMPTS_LIST_MAX_LIMIT: i64 = 100;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum MerchantIdOrProfileId {
|
||||||
|
MerchantId(String),
|
||||||
|
ProfileId(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(state))]
|
#[instrument(skip(state))]
|
||||||
pub async fn list_initial_delivery_attempts(
|
pub async fn list_initial_delivery_attempts(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
merchant_id: String,
|
merchant_id_or_profile_id: String,
|
||||||
constraints: api::webhook_events::EventListConstraints,
|
constraints: api::webhook_events::EventListConstraints,
|
||||||
) -> RouterResponse<Vec<api::webhook_events::EventListItemResponse>> {
|
) -> RouterResponse<Vec<api::webhook_events::EventListItemResponse>> {
|
||||||
let constraints =
|
let constraints =
|
||||||
@ -21,24 +27,27 @@ pub async fn list_initial_delivery_attempts(
|
|||||||
|
|
||||||
let store = state.store.as_ref();
|
let store = state.store.as_ref();
|
||||||
|
|
||||||
// This would handle verifying that the merchant ID actually exists
|
let (identifier, key_store) =
|
||||||
let key_store = store
|
determine_identifier_and_get_key_store(state.clone(), merchant_id_or_profile_id).await?;
|
||||||
.get_merchant_key_store_by_merchant_id(
|
|
||||||
&merchant_id,
|
|
||||||
&store.get_master_key().to_vec().into(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
|
||||||
|
|
||||||
let events = match constraints {
|
let events = match constraints {
|
||||||
api_models::webhook_events::EventListConstraintsInternal::ObjectIdFilter { object_id } => {
|
api_models::webhook_events::EventListConstraintsInternal::ObjectIdFilter { object_id } => {
|
||||||
store
|
match identifier {
|
||||||
|
MerchantIdOrProfileId::MerchantId(merchant_id) => store
|
||||||
.list_initial_events_by_merchant_id_primary_object_id(
|
.list_initial_events_by_merchant_id_primary_object_id(
|
||||||
&merchant_id,
|
&merchant_id,
|
||||||
&object_id,
|
&object_id,
|
||||||
&key_store,
|
&key_store,
|
||||||
)
|
)
|
||||||
.await
|
.await,
|
||||||
|
MerchantIdOrProfileId::ProfileId(profile_id) => store
|
||||||
|
.list_initial_events_by_profile_id_primary_object_id(
|
||||||
|
&profile_id,
|
||||||
|
&object_id,
|
||||||
|
&key_store,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
api_models::webhook_events::EventListConstraintsInternal::GenericFilter {
|
api_models::webhook_events::EventListConstraintsInternal::GenericFilter {
|
||||||
created_after,
|
created_after,
|
||||||
@ -60,7 +69,8 @@ pub async fn list_initial_delivery_attempts(
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
store
|
match identifier {
|
||||||
|
MerchantIdOrProfileId::MerchantId(merchant_id) => store
|
||||||
.list_initial_events_by_merchant_id_constraints(
|
.list_initial_events_by_merchant_id_constraints(
|
||||||
&merchant_id,
|
&merchant_id,
|
||||||
created_after,
|
created_after,
|
||||||
@ -69,7 +79,18 @@ pub async fn list_initial_delivery_attempts(
|
|||||||
offset,
|
offset,
|
||||||
&key_store,
|
&key_store,
|
||||||
)
|
)
|
||||||
.await
|
.await,
|
||||||
|
MerchantIdOrProfileId::ProfileId(profile_id) => store
|
||||||
|
.list_initial_events_by_profile_id_constraints(
|
||||||
|
&profile_id,
|
||||||
|
created_after,
|
||||||
|
created_before,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
&key_store,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
@ -86,22 +107,36 @@ pub async fn list_initial_delivery_attempts(
|
|||||||
#[instrument(skip(state))]
|
#[instrument(skip(state))]
|
||||||
pub async fn list_delivery_attempts(
|
pub async fn list_delivery_attempts(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
merchant_id: &str,
|
merchant_id_or_profile_id: String,
|
||||||
initial_attempt_id: &str,
|
initial_attempt_id: String,
|
||||||
) -> RouterResponse<Vec<api::webhook_events::EventRetrieveResponse>> {
|
) -> RouterResponse<Vec<api::webhook_events::EventRetrieveResponse>> {
|
||||||
let store = state.store.as_ref();
|
let store = state.store.as_ref();
|
||||||
|
|
||||||
// This would handle verifying that the merchant ID actually exists
|
let (identifier, key_store) =
|
||||||
let key_store = store
|
determine_identifier_and_get_key_store(state.clone(), merchant_id_or_profile_id).await?;
|
||||||
.get_merchant_key_store_by_merchant_id(merchant_id, &store.get_master_key().to_vec().into())
|
|
||||||
.await
|
|
||||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
|
||||||
|
|
||||||
let events = store
|
let events = match identifier {
|
||||||
.list_events_by_merchant_id_initial_attempt_id(merchant_id, initial_attempt_id, &key_store)
|
MerchantIdOrProfileId::MerchantId(merchant_id) => {
|
||||||
.await
|
store
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.list_events_by_merchant_id_initial_attempt_id(
|
||||||
.attach_printable("Failed to list delivery attempts for initial event")?;
|
&merchant_id,
|
||||||
|
&initial_attempt_id,
|
||||||
|
&key_store,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
MerchantIdOrProfileId::ProfileId(profile_id) => {
|
||||||
|
store
|
||||||
|
.list_events_by_profile_id_initial_attempt_id(
|
||||||
|
&profile_id,
|
||||||
|
&initial_attempt_id,
|
||||||
|
&key_store,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to list delivery attempts for initial event")?;
|
||||||
|
|
||||||
if events.is_empty() {
|
if events.is_empty() {
|
||||||
Err(error_stack::report!(
|
Err(error_stack::report!(
|
||||||
@ -117,3 +152,56 @@ pub async fn list_delivery_attempts(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn determine_identifier_and_get_key_store(
|
||||||
|
state: AppState,
|
||||||
|
merchant_id_or_profile_id: String,
|
||||||
|
) -> errors::RouterResult<(MerchantIdOrProfileId, domain::MerchantKeyStore)> {
|
||||||
|
let store = state.store.as_ref();
|
||||||
|
match store
|
||||||
|
.get_merchant_key_store_by_merchant_id(
|
||||||
|
&merchant_id_or_profile_id,
|
||||||
|
&store.get_master_key().to_vec().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
// Valid merchant ID
|
||||||
|
Ok(key_store) => Ok((
|
||||||
|
MerchantIdOrProfileId::MerchantId(merchant_id_or_profile_id),
|
||||||
|
key_store,
|
||||||
|
)),
|
||||||
|
|
||||||
|
// Invalid merchant ID, check if we can find a business profile with the identifier
|
||||||
|
Err(error) if error.current_context().is_db_not_found() => {
|
||||||
|
router_env::logger::debug!(
|
||||||
|
?error,
|
||||||
|
%merchant_id_or_profile_id,
|
||||||
|
"Failed to find merchant key store for the specified merchant ID or business profile ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
let business_profile = store
|
||||||
|
.find_business_profile_by_profile_id(&merchant_id_or_profile_id)
|
||||||
|
.await
|
||||||
|
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||||
|
id: merchant_id_or_profile_id,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let key_store = store
|
||||||
|
.get_merchant_key_store_by_merchant_id(
|
||||||
|
&business_profile.merchant_id,
|
||||||
|
&store.get_master_key().to_vec().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
MerchantIdOrProfileId::ProfileId(business_profile.profile_id),
|
||||||
|
key_store,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(error) => Err(error)
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to find merchant key store by merchant ID"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1224,7 +1224,7 @@ pub struct WebhookEvents;
|
|||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
impl WebhookEvents {
|
impl WebhookEvents {
|
||||||
pub fn server(config: AppState) -> Scope {
|
pub fn server(config: AppState) -> Scope {
|
||||||
web::scope("/events/{merchant_id}")
|
web::scope("/events/{merchant_id_or_profile_id}")
|
||||||
.app_data(web::Data::new(config))
|
.app_data(web::Data::new(config))
|
||||||
.service(web::resource("").route(web::get().to(list_initial_webhook_delivery_attempts)))
|
.service(web::resource("").route(web::get().to(list_initial_webhook_delivery_attempts)))
|
||||||
.service(
|
.service(
|
||||||
|
|||||||
@ -5,7 +5,9 @@ use crate::{
|
|||||||
core::{api_locking, webhooks::webhook_events},
|
core::{api_locking, webhooks::webhook_events},
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
services::{api, authentication as auth, authorization::permissions::Permission},
|
services::{api, authentication as auth, authorization::permissions::Permission},
|
||||||
types::api::webhook_events::{EventListConstraints, EventListRequestInternal},
|
types::api::webhook_events::{
|
||||||
|
EventListConstraints, EventListRequestInternal, WebhookDeliveryAttemptListRequestInternal,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[instrument(skip_all, fields(flow = ?Flow::WebhookEventInitialDeliveryAttemptList))]
|
#[instrument(skip_all, fields(flow = ?Flow::WebhookEventInitialDeliveryAttemptList))]
|
||||||
@ -16,11 +18,11 @@ pub async fn list_initial_webhook_delivery_attempts(
|
|||||||
query: web::Query<EventListConstraints>,
|
query: web::Query<EventListConstraints>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let flow = Flow::WebhookEventInitialDeliveryAttemptList;
|
let flow = Flow::WebhookEventInitialDeliveryAttemptList;
|
||||||
let merchant_id = path.into_inner();
|
let merchant_id_or_profile_id = path.into_inner();
|
||||||
let constraints = query.into_inner();
|
let constraints = query.into_inner();
|
||||||
|
|
||||||
let request_internal = EventListRequestInternal {
|
let request_internal = EventListRequestInternal {
|
||||||
merchant_id: merchant_id.clone(),
|
merchant_id_or_profile_id: merchant_id_or_profile_id.clone(),
|
||||||
constraints,
|
constraints,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,14 +34,14 @@ pub async fn list_initial_webhook_delivery_attempts(
|
|||||||
|state, _, request_internal| {
|
|state, _, request_internal| {
|
||||||
webhook_events::list_initial_delivery_attempts(
|
webhook_events::list_initial_delivery_attempts(
|
||||||
state,
|
state,
|
||||||
request_internal.merchant_id,
|
request_internal.merchant_id_or_profile_id,
|
||||||
request_internal.constraints,
|
request_internal.constraints,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
auth::auth_type(
|
auth::auth_type(
|
||||||
&auth::AdminApiAuth,
|
&auth::AdminApiAuth,
|
||||||
&auth::JWTAuthMerchantFromRoute {
|
&auth::JWTAuthMerchantOrProfileFromRoute {
|
||||||
merchant_id,
|
merchant_id_or_profile_id,
|
||||||
required_permission: Permission::WebhookEventRead,
|
required_permission: Permission::WebhookEventRead,
|
||||||
},
|
},
|
||||||
req.headers(),
|
req.headers(),
|
||||||
@ -56,20 +58,29 @@ pub async fn list_webhook_delivery_attempts(
|
|||||||
path: web::Path<(String, String)>,
|
path: web::Path<(String, String)>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let flow = Flow::WebhookEventDeliveryAttemptList;
|
let flow = Flow::WebhookEventDeliveryAttemptList;
|
||||||
let (merchant_id, initial_event_id) = path.into_inner();
|
let (merchant_id_or_profile_id, initial_attempt_id) = path.into_inner();
|
||||||
|
|
||||||
|
let request_internal = WebhookDeliveryAttemptListRequestInternal {
|
||||||
|
merchant_id_or_profile_id: merchant_id_or_profile_id.clone(),
|
||||||
|
initial_attempt_id,
|
||||||
|
};
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state,
|
state,
|
||||||
&req,
|
&req,
|
||||||
(&merchant_id, &initial_event_id),
|
request_internal,
|
||||||
|state, _, (merchant_id, initial_event_id)| {
|
|state, _, request_internal| {
|
||||||
webhook_events::list_delivery_attempts(state, merchant_id, initial_event_id)
|
webhook_events::list_delivery_attempts(
|
||||||
|
state,
|
||||||
|
request_internal.merchant_id_or_profile_id,
|
||||||
|
request_internal.initial_attempt_id,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
auth::auth_type(
|
auth::auth_type(
|
||||||
&auth::AdminApiAuth,
|
&auth::AdminApiAuth,
|
||||||
&auth::JWTAuthMerchantFromRoute {
|
&auth::JWTAuthMerchantOrProfileFromRoute {
|
||||||
merchant_id: merchant_id.clone(),
|
merchant_id_or_profile_id,
|
||||||
required_permission: Permission::WebhookEventRead,
|
required_permission: Permission::WebhookEventRead,
|
||||||
},
|
},
|
||||||
req.headers(),
|
req.headers(),
|
||||||
|
|||||||
@ -531,6 +531,68 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct JWTAuthMerchantOrProfileFromRoute {
|
||||||
|
pub merchant_id_or_profile_id: String,
|
||||||
|
pub required_permission: Permission,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<A> AuthenticateAndFetch<(), A> for JWTAuthMerchantOrProfileFromRoute
|
||||||
|
where
|
||||||
|
A: AppStateInfo + Sync,
|
||||||
|
{
|
||||||
|
async fn authenticate_and_fetch(
|
||||||
|
&self,
|
||||||
|
request_headers: &HeaderMap,
|
||||||
|
state: &A,
|
||||||
|
) -> RouterResult<((), AuthenticationType)> {
|
||||||
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if payload.check_in_blacklist(state).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let permissions = authorization::get_permissions(state, &payload).await?;
|
||||||
|
authorization::check_authorization(&self.required_permission, &permissions)?;
|
||||||
|
|
||||||
|
// Check if token has access to MerchantId that has been requested through path or query param
|
||||||
|
if payload.merchant_id == self.merchant_id_or_profile_id {
|
||||||
|
return Ok((
|
||||||
|
(),
|
||||||
|
AuthenticationType::MerchantJwt {
|
||||||
|
merchant_id: payload.merchant_id,
|
||||||
|
user_id: Some(payload.user_id),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route did not contain the merchant ID in present JWT, check if it corresponds to a
|
||||||
|
// business profile
|
||||||
|
let business_profile = state
|
||||||
|
.store()
|
||||||
|
.find_business_profile_by_profile_id(&self.merchant_id_or_profile_id)
|
||||||
|
.await
|
||||||
|
// Return access forbidden if business profile not found
|
||||||
|
.to_not_found_response(errors::ApiErrorResponse::AccessForbidden {
|
||||||
|
resource: self.merchant_id_or_profile_id.clone(),
|
||||||
|
})
|
||||||
|
.attach_printable("Could not find business profile specified in route")?;
|
||||||
|
|
||||||
|
// Check if merchant (from JWT) has access to business profile that has been requested
|
||||||
|
// through path or query param
|
||||||
|
if payload.merchant_id == business_profile.merchant_id {
|
||||||
|
Ok((
|
||||||
|
(),
|
||||||
|
AuthenticationType::MerchantJwt {
|
||||||
|
merchant_id: payload.merchant_id,
|
||||||
|
user_id: Some(payload.user_id),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(report!(errors::ApiErrorResponse::InvalidJwtToken))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn parse_jwt_payload<A, T>(headers: &HeaderMap, state: &A) -> RouterResult<T>
|
pub async fn parse_jwt_payload<A, T>(headers: &HeaderMap, state: &A) -> RouterResult<T>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
pub use api_models::webhook_events::{
|
pub use api_models::webhook_events::{
|
||||||
EventListConstraints, EventListConstraintsInternal, EventListItemResponse,
|
EventListConstraints, EventListConstraintsInternal, EventListItemResponse,
|
||||||
EventListRequestInternal, EventRetrieveResponse, OutgoingWebhookRequestContent,
|
EventListRequestInternal, EventRetrieveResponse, OutgoingWebhookRequestContent,
|
||||||
OutgoingWebhookResponseContent,
|
OutgoingWebhookResponseContent, WebhookDeliveryAttemptListRequestInternal,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4325,19 +4325,19 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/events/{merchant_id}": {
|
"/events/{merchant_id_or_profile_id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"Event"
|
"Event"
|
||||||
],
|
],
|
||||||
"summary": "Events - List",
|
"summary": "Events - List",
|
||||||
"description": "Events - List\n\nList all Events associated with a Merchant Account.",
|
"description": "Events - List\n\nList all Events associated with a Merchant Account or Business Profile.",
|
||||||
"operationId": "List all Events associated with a Merchant Account",
|
"operationId": "List all Events associated with a Merchant Account or Business Profile",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "merchant_id",
|
"name": "merchant_id_or_profile_id",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "The unique identifier for the Merchant Account",
|
"description": "The unique identifier for the Merchant Account or Business Profile",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4420,7 +4420,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/events/{merchant_id}/{event_id}/attempts": {
|
"/events/{merchant_id_or_profile_id}/{event_id}/attempts": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"Event"
|
"Event"
|
||||||
@ -4430,9 +4430,9 @@
|
|||||||
"operationId": "List all delivery attempts for an Event",
|
"operationId": "List all delivery attempts for an Event",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "merchant_id",
|
"name": "merchant_id_or_profile_id",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "The unique identifier for the Merchant Account",
|
"description": "The unique identifier for the Merchant Account or Business Profile",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|||||||
Reference in New Issue
Block a user