diff --git a/Cargo.lock b/Cargo.lock index 6f69d9752f62..158b628e7f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2366,6 +2366,7 @@ dependencies = [ "serde_json", "strum 0.25.0", "thiserror", + "utoipa", ] [[package]] diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index ddb786d2d686..eebb084d30d2 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -43,7 +43,8 @@ pub struct MerchantAccountCreate { pub webhook_details: Option, /// The routing algorithm to be used for routing payments to desired connectors - #[schema(value_type = Option,example = json!({"type": "single", "data": "stripe"}))] + #[serde(skip)] + #[schema(deprecated)] pub routing_algorithm: Option, /// The routing algorithm to be used for routing payouts to desired connectors @@ -135,7 +136,8 @@ pub struct MerchantAccountUpdate { pub webhook_details: Option, /// The routing algorithm to be used for routing payments to desired connectors - #[schema(value_type = Option,example = json!({"type": "single", "data": "stripe"}))] + #[serde(skip)] + #[schema(deprecated)] pub routing_algorithm: Option, /// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom' @@ -233,7 +235,8 @@ pub struct MerchantAccountResponse { pub webhook_details: Option, /// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom' - #[schema(value_type = Option, max_length = 255, example = "custom")] + #[serde(skip)] + #[schema(deprecated)] pub routing_algorithm: Option, /// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom' diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 558223a68eed..570a6dfb6e7c 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -13,11 +13,9 @@ use utoipa::ToSchema; serde::Serialize, strum::Display, strum::EnumString, - ToSchema, )] /// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom' -#[schema(example = "custom")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RoutingAlgorithm { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index ba60782f8f7b..3dca09e12213 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -119,9 +119,9 @@ pub struct PaymentsRequest { #[schema(max_length = 255, example = "merchant_1668273825")] pub merchant_id: Option, - #[schema(value_type = Option, example = json!({ + #[schema(value_type = Option, example = json!({ "type": "single", - "data": "stripe" + "data": {"connector": "stripe", "merchant_connector_id": "mca_123"} }))] pub routing: Option, diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 2236714da1d1..f3a9688fd96f 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use common_utils::errors::ParsingError; use error_stack::IntoReport; -use euclid::{ +pub use euclid::{ dssa::types::EuclidAnalysable, frontend::{ ast, @@ -10,10 +10,11 @@ use euclid::{ }, }; use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; use crate::enums::{self, RoutableConnectors}; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(tag = "type", content = "data", rename_all = "snake_case")] pub enum ConnectorSelection { Priority(Vec), @@ -31,7 +32,7 @@ impl ConnectorSelection { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct RoutingConfigRequest { pub name: Option, pub description: Option, @@ -39,7 +40,7 @@ pub struct RoutingConfigRequest { pub profile_id: Option, } -#[derive(Debug, serde::Serialize)] +#[derive(Debug, serde::Serialize, ToSchema)] pub struct ProfileDefaultRoutingConfig { pub profile_id: String, pub connectors: Vec, @@ -60,19 +61,21 @@ pub struct RoutingRetrieveLinkQuery { pub profile_id: Option, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] +/// Response of the retrieved routing configs for a merchant account pub struct RoutingRetrieveResponse { pub algorithm: Option, } -#[derive(Debug, serde::Serialize)] +#[derive(Debug, serde::Serialize, ToSchema)] #[serde(untagged)] pub enum LinkedRoutingConfigRetrieveResponse { MerchantAccountBased(RoutingRetrieveResponse), ProfileBased(Vec), } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] +/// Routing Algorithm specific to merchants pub struct MerchantRoutingAlgorithm { pub id: String, #[cfg(feature = "business_profile_routing")] @@ -153,14 +156,14 @@ impl EuclidAnalysable for ConnectorSelection { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct ConnectorVolumeSplit { pub connector: RoutableConnectorChoice, pub split: u8, } #[cfg(feature = "connector_choice_bcompat")] -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] pub enum RoutableChoiceKind { OnlyConnector, FullStruct, @@ -180,15 +183,18 @@ pub enum RoutableChoiceSerde { }, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] #[cfg_attr( feature = "connector_choice_bcompat", serde(from = "RoutableChoiceSerde"), serde(into = "RoutableChoiceSerde") )] #[cfg_attr(not(feature = "connector_choice_bcompat"), derive(PartialEq, Eq))] + +/// Routable Connector chosen for a payment pub struct RoutableConnectorChoice { #[cfg(feature = "connector_choice_bcompat")] + #[serde(skip)] pub choice_kind: RoutableChoiceKind, pub connector: RoutableConnectors, #[cfg(feature = "connector_choice_mca_id")] @@ -322,7 +328,7 @@ impl DetailedConnectorChoice { } } -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, strum::Display)] +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, strum::Display, ToSchema)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RoutingAlgorithmKind { @@ -339,17 +345,19 @@ pub struct RoutingPayloadWrapper { pub profile_id: String, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] #[serde( tag = "type", content = "data", rename_all = "snake_case", try_from = "RoutingAlgorithmSerde" )] +/// Routing Algorithm kind pub enum RoutingAlgorithm { Single(Box), Priority(Vec), VolumeSplit(Vec), + #[schema(value_type=ProgramConnectorSelection)] Advanced(euclid::frontend::ast::Program), } @@ -390,7 +398,7 @@ impl TryFrom for RoutingAlgorithm { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] #[serde( tag = "type", content = "data", @@ -516,7 +524,7 @@ impl RoutingAlgorithmRef { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct RoutingDictionaryRecord { pub id: String, @@ -529,14 +537,14 @@ pub struct RoutingDictionaryRecord { pub modified_at: i64, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct RoutingDictionary { pub merchant_id: String, pub active_id: Option, pub records: Vec, } -#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Debug, ToSchema)] #[serde(untagged)] pub enum RoutingKind { Config(RoutingDictionary), diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 0619cacbcf9d..7bb6a4d75ea3 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -73,10 +73,12 @@ pub enum AttemptStatus { strum::EnumString, strum::EnumIter, strum::EnumVariantNames, + ToSchema, )] #[router_derive::diesel_enum(storage_type = "db_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] +/// Connectors eligible for payments routing pub enum RoutableConnectors { #[cfg(feature = "dummy_connector")] #[serde(rename = "phonypay")] diff --git a/crates/euclid/Cargo.toml b/crates/euclid/Cargo.toml index 08b9f0af28b7..415398105aef 100644 --- a/crates/euclid/Cargo.toml +++ b/crates/euclid/Cargo.toml @@ -16,6 +16,7 @@ serde = { version = "1.0.193", features = ["derive", "rc"] } serde_json = "1.0.108" strum = { version = "0.25", features = ["derive"] } thiserror = "1.0.43" +utoipa = { version = "3.3.0", features = ["preserve_order"] } # First party dependencies common_enums = { version = "0.1.0", path = "../common_enums" } diff --git a/crates/euclid/src/frontend/ast.rs b/crates/euclid/src/frontend/ast.rs index 0dad9b53c323..949177923eec 100644 --- a/crates/euclid/src/frontend/ast.rs +++ b/crates/euclid/src/frontend/ast.rs @@ -4,6 +4,7 @@ pub mod parser; use common_enums::RoutableConnectors; use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; use crate::types::{DataType, Metadata}; @@ -14,14 +15,14 @@ pub struct ConnectorChoice { pub sub_label: Option, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct MetadataValue { pub key: String, pub value: String, } /// Represents a value in the DSL -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] #[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum ValueType { /// Represents a number literal @@ -60,7 +61,7 @@ impl ValueType { } /// Represents a number comparison for "NumberComparisonArrayValue" -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct NumberComparison { pub comparison_type: ComparisonType, @@ -68,7 +69,7 @@ pub struct NumberComparison { } /// Conditional comparison type -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum ComparisonType { Equal, @@ -80,7 +81,7 @@ pub enum ComparisonType { } /// Represents a single comparison condition. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct Comparison { /// The left hand side which will always be a domain input identifier like "payment.method.cardtype" @@ -92,6 +93,7 @@ pub struct Comparison { /// Additional metadata that the Static Analyzer and Backend does not touch. /// This can be used to store useful information for the frontend and is required for communication /// between the static analyzer and the frontend. + #[schema(value_type=HashMap)] pub metadata: Metadata, } @@ -112,9 +114,10 @@ pub type IfCondition = Vec; /// } /// } /// ``` -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct IfStatement { + #[schema(value_type=Vec)] pub condition: IfCondition, pub nested: Option>, } @@ -134,8 +137,9 @@ pub struct IfStatement { /// } /// ``` -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] +#[aliases(RuleConnectorSelection = Rule)] pub struct Rule { pub name: String, #[serde(alias = "routingOutput")] @@ -145,10 +149,44 @@ pub struct Rule { /// The program, having a default connector selection and /// a bunch of rules. Also can hold arbitrary metadata. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] +#[aliases(ProgramConnectorSelection = Program)] pub struct Program { pub default_selection: O, + #[schema(value_type=RuleConnectorSelection)] pub rules: Vec>, + #[schema(value_type=HashMap)] pub metadata: Metadata, } + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct RoutableConnectorChoice { + #[cfg(feature = "connector_choice_bcompat")] + #[serde(skip)] + pub choice_kind: RoutableChoiceKind, + // pub connector: RoutableConnectors, + #[cfg(feature = "connector_choice_mca_id")] + pub merchant_connector_id: Option, + #[cfg(not(feature = "connector_choice_mca_id"))] + pub sub_label: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub enum RoutableChoiceKind { + OnlyConnector, + FullStruct, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct ConnectorVolumeSplit { + pub connector: RoutableConnectorChoice, + pub split: u8, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(tag = "type", content = "data", rename_all = "snake_case")] +pub enum ConnectorSelection { + Priority(Vec), + VolumeSplit(Vec), +} diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index b1d135a88a9f..1e5854159390 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -63,6 +63,7 @@ Never share your secret api keys. Keep them guarded and secure. (name = "API Key", description = "Create and manage API Keys"), (name = "Payouts", description = "Create and manage payouts"), (name = "payment link", description = "Create payment link"), + (name = "Routing", description = "Create and manage routing configurations"), ), // The paths will be displayed in the same order as they are registered here paths( @@ -131,6 +132,17 @@ Never share your secret api keys. Keep them guarded and secure. routes::disputes::retrieve_dispute, routes::disputes::retrieve_disputes_list, + // Routes for routing + routes::routing::routing_create_config, + routes::routing::routing_link_config, + routes::routing::routing_retrieve_config, + routes::routing::list_routing_configs, + routes::routing::routing_unlink_config, + routes::routing::routing_update_default_config, + routes::routing::routing_retrieve_default_config, + routes::routing::routing_retrieve_linked_config, + routes::routing::routing_retrieve_default_config_for_profiles, + routes::routing::routing_update_default_config_for_profile, ), components(schemas( api_models::refunds::RefundRequest, @@ -159,7 +171,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::customers::CustomerResponse, api_models::admin::AcceptedCountries, api_models::admin::AcceptedCurrencies, - api_models::enums::RoutingAlgorithm, api_models::enums::PaymentType, api_models::enums::PaymentMethod, api_models::enums::PaymentMethodType, @@ -386,6 +397,30 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::RetrievePaymentLinkResponse, api_models::payments::PaymentLinkInitiateRequest, api_models::payments::PaymentLinkObject, + api_models::routing::RoutingConfigRequest, + api_models::routing::RoutingDictionaryRecord, + api_models::routing::RoutingKind, + api_models::routing::RoutableConnectorChoice, + api_models::routing::LinkedRoutingConfigRetrieveResponse, + api_models::routing::RoutingRetrieveResponse, + api_models::routing::ProfileDefaultRoutingConfig, + api_models::routing::MerchantRoutingAlgorithm, + api_models::routing::RoutingAlgorithmKind, + api_models::routing::RoutingDictionary, + api_models::routing::RoutingAlgorithm, + api_models::routing::StraightThroughAlgorithm, + api_models::routing::ConnectorVolumeSplit, + api_models::routing::ConnectorSelection, + api_models::routing::ast::RoutableChoiceKind, + api_models::enums::RoutableConnectors, + api_models::routing::ast::ProgramConnectorSelection, + api_models::routing::ast::RuleConnectorSelection, + api_models::routing::ast::IfStatement, + api_models::routing::ast::Comparison, + api_models::routing::ast::ComparisonType, + api_models::routing::ast::ValueType, + api_models::routing::ast::MetadataValue, + api_models::routing::ast::NumberComparison, api_models::payment_methods::RequestPaymentMethodTypes, )), modifiers(&SecurityAddon) diff --git a/crates/openapi/src/routes.rs b/crates/openapi/src/routes.rs index e0eff4e1e290..f85fc56ff2c6 100644 --- a/crates/openapi/src/routes.rs +++ b/crates/openapi/src/routes.rs @@ -10,6 +10,7 @@ pub mod merchant_connector_account; pub mod payment_method; pub mod payments; pub mod refunds; +pub mod routing; pub use customers::*; pub use mandates::*; @@ -18,3 +19,4 @@ pub use merchant_connector_account::*; pub use payment_method::*; pub use payments::*; pub use refunds::*; +pub use routing::*; diff --git a/crates/openapi/src/routes/routing.rs b/crates/openapi/src/routes/routing.rs new file mode 100644 index 000000000000..ecfac39f9e9a --- /dev/null +++ b/crates/openapi/src/routes/routing.rs @@ -0,0 +1,202 @@ +/// Routing - Create +/// +/// Create a routing config +#[utoipa::path( + post, + path = "/routing", + request_body = RoutingConfigRequest, + responses( + (status = 200, description = "Routing config created", body = RoutingDictionaryRecord), + (status = 400, description = "Request body is malformed"), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing"), + (status = 422, description = "Unprocessable request"), + (status = 403, description = "Forbidden"), + ), + tag = "Routing", + operation_id = "Create a routing config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_create_config() {} + +/// Routing - Activate config +/// +/// Activate a routing config +#[utoipa::path( + post, + path = "/routing/{algorithm_id}/activate", + params( + ("algorithm_id" = String, Path, description = "The unique identifier for a config"), + ), + responses( + (status = 200, description = "Routing config activated", body = RoutingDictionaryRecord), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing"), + (status = 400, description = "Bad request") + ), + tag = "Routing", + operation_id = "Activate a routing config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_link_config() {} + +/// Routing - Retrieve +/// +/// Retrieve a routing algorithm + +#[utoipa::path( + get, + path = "/routing/{algorithm_id}", + params( + ("algorithm_id" = String, Path, description = "The unique identifier for a config"), + ), + responses( + (status = 200, description = "Successfully fetched routing config", body = MerchantRoutingAlgorithm), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing"), + (status = 403, description = "Forbidden") + ), + tag = "Routing", + operation_id = "Retrieve a routing config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_retrieve_config() {} + +/// Routing - List +/// +/// List all routing configs +#[utoipa::path( + get, + path = "/routing", + params( + ("limit" = Option, Query, description = "The number of records to be returned"), + ("offset" = Option, Query, description = "The record offset from which to start gathering of results"), + ("profile_id" = Option, Query, description = "The unique identifier for a merchant profile"), + ), + responses( + (status = 200, description = "Successfully fetched routing configs", body = RoutingKind), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing") + ), + tag = "Routing", + operation_id = "List routing configs", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn list_routing_configs() {} + +/// Routing - Deactivate +/// +/// Deactivates a routing config +#[utoipa::path( + post, + path = "/routing/deactivate", + request_body = RoutingConfigRequest, + responses( + (status = 200, description = "Successfully deactivated routing config", body = RoutingDictionaryRecord), + (status = 500, description = "Internal server error"), + (status = 400, description = "Malformed request"), + (status = 403, description = "Malformed request"), + (status = 422, description = "Unprocessable request") + ), + tag = "Routing", + operation_id = "Deactivate a routing config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_unlink_config() {} + +/// Routing - Update Default Config +/// +/// Update default fallback config +#[utoipa::path( + post, + path = "/routing/default", + request_body = Vec, + responses( + (status = 200, description = "Successfully updated default config", body = Vec), + (status = 500, description = "Internal server error"), + (status = 400, description = "Malformed request"), + (status = 422, description = "Unprocessable request") + ), + tag = "Routing", + operation_id = "Update default fallback config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_update_default_config() {} + +/// Routing - Retrieve Default Config +/// +/// Retrieve default fallback config +#[utoipa::path( + get, + path = "/routing/default", + responses( + (status = 200, description = "Successfully retrieved default config", body = Vec), + (status = 500, description = "Internal server error") + ), + tag = "Routing", + operation_id = "Retrieve default fallback config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_retrieve_default_config() {} + +/// Routing - Retrieve Config +/// +/// Retrieve active config +#[utoipa::path( + get, + path = "/routing/active", + params( + ("profile_id" = Option, Query, description = "The unique identifier for a merchant profile"), + ), + responses( + (status = 200, description = "Successfully retrieved active config", body = LinkedRoutingConfigRetrieveResponse), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing"), + (status = 403, description = "Forbidden") + ), + tag = "Routing", + operation_id = "Retrieve active config", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_retrieve_linked_config() {} + +/// Routing - Retrieve Default For Profile +/// +/// Retrieve default config for profiles +#[utoipa::path( + get, + path = "/routing/default/profile", + responses( + (status = 200, description = "Successfully retrieved default config", body = ProfileDefaultRoutingConfig), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing") + ), + tag = "Routing", + operation_id = "Retrieve default configs for all profiles", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_retrieve_default_config_for_profiles() {} + +/// Routing - Update Default For Profile +/// +/// Update default config for profiles +#[utoipa::path( + post, + path = "/routing/default/profile/{profile_id}", + request_body = Vec, + params( + ("profile_id" = String, Path, description = "The unique identifier for a profile"), + ), + responses( + (status = 200, description = "Successfully updated default config for profile", body = ProfileDefaultRoutingConfig), + (status = 500, description = "Internal server error"), + (status = 404, description = "Resource missing"), + (status = 400, description = "Malformed request"), + (status = 422, description = "Unprocessable request"), + (status = 403, description = "Forbidden"), + ), + tag = "Routing", + operation_id = "Update default configs for all profiles", + security(("api_key" = []), ("jwt_key" = [])) +)] +pub async fn routing_update_default_config_for_profile() {} diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 67aa11aa8b84..b9b9f23cbd92 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -409,7 +409,7 @@ impl Routing { ) .service( web::resource("") - .route(web::get().to(cloud_routing::routing_retrieve_dictionary)) + .route(web::get().to(cloud_routing::list_routing_configs)) .route(web::post().to(cloud_routing::routing_create_config)), ) .service( diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index e7e31cb36aeb..0f139e936146 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -113,7 +113,7 @@ pub async fn routing_retrieve_config( #[cfg(feature = "olap")] #[instrument(skip_all)] -pub async fn routing_retrieve_dictionary( +pub async fn list_routing_configs( state: web::Data, req: HttpRequest, #[cfg(feature = "business_profile_routing")] query: web::Query, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 9ddce51fe21e..8eb9c14f99ab 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -2781,6 +2781,528 @@ } ] } + }, + "/routing": { + "get": { + "tags": [ + "Routing" + ], + "summary": "Routing - List", + "description": "Routing - List\n\nList all routing configs", + "operationId": "List routing configs", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "The number of records to be returned", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "nullable": true, + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "The record offset from which to start gathering of results", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "nullable": true, + "minimum": 0 + } + }, + { + "name": "profile_id", + "in": "query", + "description": "The unique identifier for a merchant profile", + "required": false, + "schema": { + "type": "string", + "nullable": true + } + } + ], + "responses": { + "200": { + "description": "Successfully fetched routing configs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingKind" + } + } + } + }, + "404": { + "description": "Resource missing" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + }, + "post": { + "tags": [ + "Routing" + ], + "summary": "Routing - Create", + "description": "Routing - Create\n\nCreate a routing config", + "operationId": "Create a routing config", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingConfigRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Routing config created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } + } + } + }, + "400": { + "description": "Request body is malformed" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Resource missing" + }, + "422": { + "description": "Unprocessable request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/active": { + "get": { + "tags": [ + "Routing" + ], + "summary": "Routing - Retrieve Config", + "description": "Routing - Retrieve Config\n\nRetrieve active config", + "operationId": "Retrieve active config", + "parameters": [ + { + "name": "profile_id", + "in": "query", + "description": "The unique identifier for a merchant profile", + "required": false, + "schema": { + "type": "string", + "nullable": true + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved active config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkedRoutingConfigRetrieveResponse" + } + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Resource missing" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/deactivate": { + "post": { + "tags": [ + "Routing" + ], + "summary": "Routing - Deactivate", + "description": "Routing - Deactivate\n\nDeactivates a routing config", + "operationId": "Deactivate a routing config", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingConfigRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully deactivated routing config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } + } + } + }, + "400": { + "description": "Malformed request" + }, + "403": { + "description": "Malformed request" + }, + "422": { + "description": "Unprocessable request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/default": { + "get": { + "tags": [ + "Routing" + ], + "summary": "Routing - Retrieve Default Config", + "description": "Routing - Retrieve Default Config\n\nRetrieve default fallback config", + "operationId": "Retrieve default fallback config", + "responses": { + "200": { + "description": "Successfully retrieved default config", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + }, + "post": { + "tags": [ + "Routing" + ], + "summary": "Routing - Update Default Config", + "description": "Routing - Update Default Config\n\nUpdate default fallback config", + "operationId": "Update default fallback config", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated default config", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + } + }, + "400": { + "description": "Malformed request" + }, + "422": { + "description": "Unprocessable request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/default/profile": { + "get": { + "tags": [ + "Routing" + ], + "summary": "Routing - Retrieve Default For Profile", + "description": "Routing - Retrieve Default For Profile\n\nRetrieve default config for profiles", + "operationId": "Retrieve default configs for all profiles", + "responses": { + "200": { + "description": "Successfully retrieved default config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProfileDefaultRoutingConfig" + } + } + } + }, + "404": { + "description": "Resource missing" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/default/profile/{profile_id}": { + "post": { + "tags": [ + "Routing" + ], + "summary": "Routing - Update Default For Profile", + "description": "Routing - Update Default For Profile\n\nUpdate default config for profiles", + "operationId": "Update default configs for all profiles", + "parameters": [ + { + "name": "profile_id", + "in": "path", + "description": "The unique identifier for a profile", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated default config for profile", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProfileDefaultRoutingConfig" + } + } + } + }, + "400": { + "description": "Malformed request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Resource missing" + }, + "422": { + "description": "Unprocessable request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/{algorithm_id}": { + "get": { + "tags": [ + "Routing" + ], + "summary": "Routing - Retrieve", + "description": "Routing - Retrieve\n\nRetrieve a routing algorithm", + "operationId": "Retrieve a routing config", + "parameters": [ + { + "name": "algorithm_id", + "in": "path", + "description": "The unique identifier for a config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully fetched routing config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MerchantRoutingAlgorithm" + } + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Resource missing" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } + }, + "/routing/{algorithm_id}/activate": { + "post": { + "tags": [ + "Routing" + ], + "summary": "Routing - Activate config", + "description": "Routing - Activate config\n\nActivate a routing config", + "operationId": "Activate a routing config", + "parameters": [ + { + "name": "algorithm_id", + "in": "path", + "description": "The unique identifier for a config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Routing config activated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "404": { + "description": "Resource missing" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + }, + { + "jwt_key": [] + } + ] + } } }, "components": { @@ -5060,6 +5582,45 @@ "CashappQr": { "type": "object" }, + "Comparison": { + "type": "object", + "description": "Represents a single comparison condition.", + "required": [ + "lhs", + "comparison", + "value", + "metadata" + ], + "properties": { + "lhs": { + "type": "string", + "description": "The left hand side which will always be a domain input identifier like \"payment.method.cardtype\"" + }, + "comparison": { + "$ref": "#/components/schemas/ComparisonType" + }, + "value": { + "$ref": "#/components/schemas/ValueType" + }, + "metadata": { + "type": "object", + "description": "Additional metadata that the Static Analyzer and Backend does not touch.\nThis can be used to store useful information for the frontend and is required for communication\nbetween the static analyzer and the frontend.", + "additionalProperties": {} + } + } + }, + "ComparisonType": { + "type": "string", + "description": "Conditional comparison type", + "enum": [ + "equal", + "not_equal", + "less_than", + "less_than_equal", + "greater_than", + "greater_than_equal" + ] + }, "Connector": { "type": "string", "enum": [ @@ -5146,6 +5707,55 @@ } } }, + "ConnectorSelection": { + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "priority" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "volume_split" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectorVolumeSplit" + } + } + } + } + ], + "discriminator": { + "propertyName": "type" + } + }, "ConnectorStatus": { "type": "string", "enum": [ @@ -5167,6 +5777,23 @@ "payment_method_auth" ] }, + "ConnectorVolumeSplit": { + "type": "object", + "required": [ + "connector", + "split" + ], + "properties": { + "connector": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + }, + "split": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + }, "CountryAlpha2": { "type": "string", "enum": [ @@ -7199,6 +7826,28 @@ } } }, + "IfStatement": { + "type": "object", + "description": "Represents an IF statement with conditions and optional nested IF statements\n\n```text\npayment.method = card {\npayment.method.cardtype = (credit, debit) {\npayment.method.network = (amex, rupay, diners)\n}\n}\n```", + "required": [ + "condition" + ], + "properties": { + "condition": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comparison" + } + }, + "nested": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IfStatement" + }, + "nullable": true + } + } + }, "IncrementalAuthorizationResponse": { "type": "object", "required": [ @@ -7329,6 +7978,19 @@ } } }, + "LinkedRoutingConfigRetrieveResponse": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutingRetrieveResponse" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } + } + ] + }, "MandateAmountData": { "type": "object", "required": [ @@ -7595,11 +8257,6 @@ ], "nullable": true }, - "routing_algorithm": { - "type": "object", - "description": "The routing algorithm to be used for routing payments to desired connectors", - "nullable": true - }, "payout_routing_algorithm": { "allOf": [ { @@ -7780,14 +8437,6 @@ ], "nullable": true }, - "routing_algorithm": { - "allOf": [ - { - "$ref": "#/components/schemas/RoutingAlgorithm" - } - ], - "nullable": true - }, "payout_routing_algorithm": { "allOf": [ { @@ -7912,11 +8561,6 @@ ], "nullable": true }, - "routing_algorithm": { - "type": "object", - "description": "The routing algorithm to be used for routing payments to desired connectors", - "nullable": true - }, "payout_routing_algorithm": { "allOf": [ { @@ -8573,20 +9217,69 @@ "nullable": true, "maxLength": 255 }, - "about_business": { - "type": "string", - "description": "A brief description about merchant's business", - "example": "Online Retail with a wide selection of organic products for North America", - "nullable": true, - "maxLength": 255 + "about_business": { + "type": "string", + "description": "A brief description about merchant's business", + "example": "Online Retail with a wide selection of organic products for North America", + "nullable": true, + "maxLength": 255 + }, + "address": { + "allOf": [ + { + "$ref": "#/components/schemas/AddressDetails" + } + ], + "nullable": true + } + } + }, + "MerchantRoutingAlgorithm": { + "type": "object", + "description": "Routing Algorithm specific to merchants", + "required": [ + "id", + "name", + "description", + "algorithm", + "created_at", + "modified_at" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "algorithm": { + "$ref": "#/components/schemas/RoutingAlgorithm" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "modified_at": { + "type": "integer", + "format": "int64" + } + } + }, + "MetadataValue": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" }, - "address": { - "allOf": [ - { - "$ref": "#/components/schemas/AddressDetails" - } - ], - "nullable": true + "value": { + "type": "string" } } }, @@ -8855,6 +9548,23 @@ } } }, + "NumberComparison": { + "type": "object", + "description": "Represents a number comparison for \"NumberComparisonArrayValue\"", + "required": [ + "comparisonType", + "number" + ], + "properties": { + "comparisonType": { + "$ref": "#/components/schemas/ComparisonType" + }, + "number": { + "type": "integer", + "format": "int64" + } + } + }, "OnlineMandate": { "type": "object", "required": [ @@ -10298,7 +11008,7 @@ "routing": { "allOf": [ { - "$ref": "#/components/schemas/RoutingAlgorithm" + "$ref": "#/components/schemas/StraightThroughAlgorithm" } ], "nullable": true @@ -10640,7 +11350,7 @@ "routing": { "allOf": [ { - "$ref": "#/components/schemas/RoutingAlgorithm" + "$ref": "#/components/schemas/StraightThroughAlgorithm" } ], "nullable": true @@ -11006,7 +11716,7 @@ "routing": { "allOf": [ { - "$ref": "#/components/schemas/RoutingAlgorithm" + "$ref": "#/components/schemas/StraightThroughAlgorithm" } ], "nullable": true @@ -11969,7 +12679,7 @@ "routing": { "allOf": [ { - "$ref": "#/components/schemas/RoutingAlgorithm" + "$ref": "#/components/schemas/StraightThroughAlgorithm" } ], "nullable": true @@ -12797,6 +13507,45 @@ "accommodation" ] }, + "ProfileDefaultRoutingConfig": { + "type": "object", + "required": [ + "profile_id", + "connectors" + ], + "properties": { + "profile_id": { + "type": "string" + }, + "connectors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + }, + "ProgramConnectorSelection": { + "type": "object", + "description": "The program, having a default connector selection and\na bunch of rules. Also can hold arbitrary metadata.", + "required": [ + "defaultSelection", + "rules", + "metadata" + ], + "properties": { + "defaultSelection": { + "$ref": "#/components/schemas/ConnectorSelection" + }, + "rules": { + "$ref": "#/components/schemas/RuleConnectorSelection" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + } + } + }, "ReceiverDetails": { "type": "object", "required": [ @@ -13184,219 +13933,513 @@ } } }, - "RequestSurchargeDetails": { + "RequestSurchargeDetails": { + "type": "object", + "required": [ + "surcharge_amount" + ], + "properties": { + "surcharge_amount": { + "type": "integer", + "format": "int64" + }, + "tax_amount": { + "type": "integer", + "format": "int64", + "nullable": true + } + } + }, + "RequiredFieldInfo": { + "type": "object", + "description": "Required fields info used while listing the payment_method_data", + "required": [ + "required_field", + "display_name", + "field_type" + ], + "properties": { + "required_field": { + "type": "string", + "description": "Required field for a payment_method through a payment_method_type" + }, + "display_name": { + "type": "string", + "description": "Display name of the required field in the front-end" + }, + "field_type": { + "$ref": "#/components/schemas/FieldType" + }, + "value": { + "type": "string", + "nullable": true + } + } + }, + "RetrieveApiKeyResponse": { + "type": "object", + "description": "The response body for retrieving an API Key.", + "required": [ + "key_id", + "merchant_id", + "name", + "prefix", + "created", + "expiration" + ], + "properties": { + "key_id": { + "type": "string", + "description": "The identifier for the API Key.", + "example": "5hEEqkgJUyuxgSKGArHA4mWSnX", + "maxLength": 64 + }, + "merchant_id": { + "type": "string", + "description": "The identifier for the Merchant Account.", + "example": "y3oqhf46pyzuxjbcn2giaqnb44", + "maxLength": 64 + }, + "name": { + "type": "string", + "description": "The unique name for the API Key to help you identify it.", + "example": "Sandbox integration key", + "maxLength": 64 + }, + "description": { + "type": "string", + "description": "The description to provide more context about the API Key.", + "example": "Key used by our developers to integrate with the sandbox environment", + "nullable": true, + "maxLength": 256 + }, + "prefix": { + "type": "string", + "description": "The first few characters of the plaintext API Key to help you identify it.", + "maxLength": 64 + }, + "created": { + "type": "string", + "format": "date-time", + "description": "The time at which the API Key was created.", + "example": "2022-09-10T10:11:12Z" + }, + "expiration": { + "$ref": "#/components/schemas/ApiKeyExpiration" + } + } + }, + "RetrievePaymentLinkRequest": { + "type": "object", + "properties": { + "client_secret": { + "type": "string", + "nullable": true + } + } + }, + "RetrievePaymentLinkResponse": { + "type": "object", + "required": [ + "payment_link_id", + "merchant_id", + "link_to_pay", + "amount", + "created_at", + "status" + ], + "properties": { + "payment_link_id": { + "type": "string" + }, + "merchant_id": { + "type": "string" + }, + "link_to_pay": { + "type": "string" + }, + "amount": { + "type": "integer", + "format": "int64" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "link_expiry": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string" + }, + "currency": { + "allOf": [ + { + "$ref": "#/components/schemas/Currency" + } + ], + "nullable": true + } + } + }, + "RetryAction": { + "type": "string", + "enum": [ + "manual_retry", + "requeue" + ] + }, + "RevokeApiKeyResponse": { + "type": "object", + "description": "The response body for revoking an API Key.", + "required": [ + "merchant_id", + "key_id", + "revoked" + ], + "properties": { + "merchant_id": { + "type": "string", + "description": "The identifier for the Merchant Account.", + "example": "y3oqhf46pyzuxjbcn2giaqnb44", + "maxLength": 64 + }, + "key_id": { + "type": "string", + "description": "The identifier for the API Key.", + "example": "5hEEqkgJUyuxgSKGArHA4mWSnX", + "maxLength": 64 + }, + "revoked": { + "type": "boolean", + "description": "Indicates whether the API key was revoked or not.", + "example": "true" + } + } + }, + "RewardData": { "type": "object", "required": [ - "surcharge_amount" + "merchant_id" ], "properties": { - "surcharge_amount": { - "type": "integer", - "format": "int64" - }, - "tax_amount": { - "type": "integer", - "format": "int64", - "nullable": true + "merchant_id": { + "type": "string", + "description": "The merchant ID with which we have to call the connector" } } }, - "RequiredFieldInfo": { + "RoutableChoiceKind": { + "type": "string", + "enum": [ + "OnlyConnector", + "FullStruct" + ] + }, + "RoutableConnectorChoice": { "type": "object", - "description": "Required fields info used while listing the payment_method_data", + "description": "Routable Connector chosen for a payment", "required": [ - "required_field", - "display_name", - "field_type" + "connector" ], "properties": { - "required_field": { - "type": "string", - "description": "Required field for a payment_method through a payment_method_type" + "connector": { + "$ref": "#/components/schemas/RoutableConnectors" }, - "display_name": { + "sub_label": { "type": "string", - "description": "Display name of the required field in the front-end" + "nullable": true + } + } + }, + "RoutableConnectors": { + "type": "string", + "description": "Connectors eligible for payments routing", + "enum": [ + "aci", + "adyen", + "airwallex", + "authorizedotnet", + "bankofamerica", + "bitpay", + "bambora", + "bluesnap", + "boku", + "braintree", + "cashtocode", + "checkout", + "coinbase", + "cryptopay", + "cybersource", + "dlocal", + "fiserv", + "forte", + "globalpay", + "globepay", + "gocardless", + "helcim", + "iatapay", + "klarna", + "mollie", + "multisafepay", + "nexinets", + "nmi", + "noon", + "nuvei", + "opennode", + "payme", + "paypal", + "payu", + "placetopay", + "powertranz", + "prophetpay", + "rapyd", + "riskified", + "shift4", + "signifyd", + "square", + "stax", + "stripe", + "trustpay", + "tsys", + "volt", + "wise", + "worldline", + "worldpay", + "zen" + ] + }, + "RoutingAlgorithm": { + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "single" + ] + }, + "data": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } }, - "field_type": { - "$ref": "#/components/schemas/FieldType" + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "priority" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } }, - "value": { - "type": "string", - "nullable": true + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "volume_split" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectorVolumeSplit" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "advanced" + ] + }, + "data": { + "$ref": "#/components/schemas/ProgramConnectorSelection" + } + } } + ], + "description": "Routing Algorithm kind", + "discriminator": { + "propertyName": "type" } }, - "RetrieveApiKeyResponse": { + "RoutingAlgorithmKind": { + "type": "string", + "enum": [ + "single", + "priority", + "volume_split", + "advanced" + ] + }, + "RoutingConfigRequest": { "type": "object", - "description": "The response body for retrieving an API Key.", - "required": [ - "key_id", - "merchant_id", - "name", - "prefix", - "created", - "expiration" - ], "properties": { - "key_id": { - "type": "string", - "description": "The identifier for the API Key.", - "example": "5hEEqkgJUyuxgSKGArHA4mWSnX", - "maxLength": 64 - }, - "merchant_id": { - "type": "string", - "description": "The identifier for the Merchant Account.", - "example": "y3oqhf46pyzuxjbcn2giaqnb44", - "maxLength": 64 - }, "name": { "type": "string", - "description": "The unique name for the API Key to help you identify it.", - "example": "Sandbox integration key", - "maxLength": 64 + "nullable": true }, "description": { "type": "string", - "description": "The description to provide more context about the API Key.", - "example": "Key used by our developers to integrate with the sandbox environment", - "nullable": true, - "maxLength": 256 + "nullable": true }, - "prefix": { - "type": "string", - "description": "The first few characters of the plaintext API Key to help you identify it.", - "maxLength": 64 + "algorithm": { + "allOf": [ + { + "$ref": "#/components/schemas/RoutingAlgorithm" + } + ], + "nullable": true }, - "created": { + "profile_id": { "type": "string", - "format": "date-time", - "description": "The time at which the API Key was created.", - "example": "2022-09-10T10:11:12Z" - }, - "expiration": { - "$ref": "#/components/schemas/ApiKeyExpiration" + "nullable": true } } }, - "RetrievePaymentLinkRequest": { + "RoutingDictionary": { "type": "object", + "required": [ + "merchant_id", + "records" + ], "properties": { - "client_secret": { + "merchant_id": { + "type": "string" + }, + "active_id": { "type": "string", "nullable": true + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } } } }, - "RetrievePaymentLinkResponse": { + "RoutingDictionaryRecord": { "type": "object", "required": [ - "payment_link_id", - "merchant_id", - "link_to_pay", - "amount", + "id", + "name", + "kind", + "description", "created_at", - "status" + "modified_at" ], "properties": { - "payment_link_id": { + "id": { "type": "string" }, - "merchant_id": { + "name": { "type": "string" }, - "link_to_pay": { + "kind": { + "$ref": "#/components/schemas/RoutingAlgorithmKind" + }, + "description": { "type": "string" }, - "amount": { + "created_at": { "type": "integer", "format": "int64" }, - "created_at": { - "type": "string", - "format": "date-time" - }, - "link_expiry": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "status": { - "type": "string" - }, - "currency": { - "allOf": [ - { - "$ref": "#/components/schemas/Currency" - } - ], - "nullable": true + "modified_at": { + "type": "integer", + "format": "int64" } } }, - "RetryAction": { - "type": "string", - "enum": [ - "manual_retry", - "requeue" + "RoutingKind": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutingDictionary" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutingDictionaryRecord" + } + } ] }, - "RevokeApiKeyResponse": { + "RoutingRetrieveResponse": { "type": "object", - "description": "The response body for revoking an API Key.", - "required": [ - "merchant_id", - "key_id", - "revoked" - ], + "description": "Response of the retrieved routing configs for a merchant account", "properties": { - "merchant_id": { - "type": "string", - "description": "The identifier for the Merchant Account.", - "example": "y3oqhf46pyzuxjbcn2giaqnb44", - "maxLength": 64 - }, - "key_id": { - "type": "string", - "description": "The identifier for the API Key.", - "example": "5hEEqkgJUyuxgSKGArHA4mWSnX", - "maxLength": 64 - }, - "revoked": { - "type": "boolean", - "description": "Indicates whether the API key was revoked or not.", - "example": "true" + "algorithm": { + "allOf": [ + { + "$ref": "#/components/schemas/MerchantRoutingAlgorithm" + } + ], + "nullable": true } } }, - "RewardData": { + "RuleConnectorSelection": { "type": "object", + "description": "Represents a rule\n\n```text\nrule_name: [stripe, adyen, checkout]\n{\npayment.method = card {\npayment.method.cardtype = (credit, debit) {\npayment.method.network = (amex, rupay, diners)\n}\n\npayment.method.cardtype = credit\n}\n}\n```", "required": [ - "merchant_id" + "name", + "connectorSelection", + "statements" ], "properties": { - "merchant_id": { - "type": "string", - "description": "The merchant ID with which we have to call the connector" + "name": { + "type": "string" + }, + "connectorSelection": { + "$ref": "#/components/schemas/ConnectorSelection" + }, + "statements": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IfStatement" + } } } }, - "RoutingAlgorithm": { - "type": "string", - "description": "The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'", - "enum": [ - "round_robin", - "max_conversion", - "min_cost", - "custom" - ], - "example": "custom" - }, "SamsungPayWalletData": { "type": "object", "required": [ @@ -13651,6 +14694,73 @@ } } }, + "StraightThroughAlgorithm": { + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "single" + ] + }, + "data": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + }, + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "priority" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutableConnectorChoice" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "data" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "volume_split" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectorVolumeSplit" + } + } + } + } + ], + "discriminator": { + "propertyName": "type" + } + }, "SurchargeDetailsResponse": { "type": "object", "required": [ @@ -13825,6 +14935,157 @@ } } }, + "ValueType": { + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "value": { + "type": "integer", + "format": "int64", + "description": "Represents a number literal" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "enum_variant" + ] + }, + "value": { + "type": "string", + "description": "Represents an enum variant" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "metadata_variant" + ] + }, + "value": { + "$ref": "#/components/schemas/MetadataValue" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "str_value" + ] + }, + "value": { + "type": "string", + "description": "Represents a arbitrary String value" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "number_array" + ] + }, + "value": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "description": "Represents an array of numbers. This is basically used for\n\"one of the given numbers\" operations\neg: payment.method.amount = (1, 2, 3)" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "enum_variant_array" + ] + }, + "value": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Similar to NumberArray but for enum variants\neg: payment.method.cardtype = (debit, credit)" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "number_comparison_array" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NumberComparison" + }, + "description": "Like a number array but can include comparisons. Useful for\nconditions like \"500 < amount < 1000\"\neg: payment.amount = (> 500, < 1000)" + } + } + } + ], + "description": "Represents a value in the DSL", + "discriminator": { + "propertyName": "type" + } + }, "VoucherData": { "oneOf": [ { @@ -14382,6 +15643,10 @@ { "name": "payment link", "description": "Create payment link" + }, + { + "name": "Routing", + "description": "Create and manage routing configurations" } ] } \ No newline at end of file