refactor: add mapping for ConnectorError in payouts flow (#2608)

Co-authored-by: Kashif <kashif@protonmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kashif <mohammed.kashif@juspay.in>
This commit is contained in:
Kashif
2023-11-21 13:04:22 +05:30
committed by GitHub
parent cfabfa60db
commit 5c4e7c9031
96 changed files with 2310 additions and 62 deletions

View File

@ -382,7 +382,7 @@ pub struct PayoutCreateResponse {
pub error_code: Option<String>,
/// The business profile that is associated with this payment
pub profile_id: Option<String>,
pub profile_id: String,
}
#[derive(Default, Debug, Clone, Deserialize, ToSchema)]

View File

@ -26,7 +26,7 @@ pub struct PayoutAttempt {
pub created_at: PrimitiveDateTime,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub last_modified_at: PrimitiveDateTime,
pub profile_id: Option<String>,
pub profile_id: String,
pub merchant_connector_id: Option<String>,
}
@ -51,7 +51,7 @@ impl Default for PayoutAttempt {
business_label: None,
created_at: now,
last_modified_at: now,
profile_id: None,
profile_id: String::default(),
merchant_connector_id: None,
}
}

View File

@ -755,7 +755,7 @@ diesel::table! {
created_at -> Timestamp,
last_modified_at -> Timestamp,
#[max_length = 64]
profile_id -> Nullable<Varchar>,
profile_id -> Varchar,
#[max_length = 32]
merchant_connector_id -> Nullable<Varchar>,
}

View File

@ -4010,8 +4010,12 @@ impl<F> TryFrom<&AdyenRouterData<&types::PayoutsRouterData<F>>> for AdyenPayoutC
iban: Some(b.iban),
tax_id: None,
},
_ => Err(errors::ConnectorError::NotSupported {
message: "Bank transfers via ACH or Bacs are not supported".to_string(),
payouts::BankPayout::Ach(..) => Err(errors::ConnectorError::NotSupported {
message: "Bank transfer via ACH is not supported".to_string(),
connector: "Adyen",
})?,
payouts::BankPayout::Bacs(..) => Err(errors::ConnectorError::NotSupported {
message: "Bank transfer via Bacs is not supported".to_string(),
connector: "Adyen",
})?,
};

View File

@ -400,6 +400,11 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
field_names: field_names.to_vec(),
}
}
errors::ConnectorError::NotSupported { message, connector } => {
errors::ApiErrorResponse::NotSupported {
message: format!("{} by {}", message, connector),
}
}
_ => errors::ApiErrorResponse::InternalServerError,
};
err.change_context(error)

View File

@ -35,6 +35,7 @@ pub struct PayoutData {
pub payout_attempt: storage::PayoutAttempt,
pub payout_method_data: Option<payouts::PayoutMethodData>,
pub merchant_connector_account: Option<payment_helpers::MerchantConnectorAccountType>,
pub profile_id: String,
}
// ********************************************** CORE FLOWS **********************************************
@ -96,9 +97,7 @@ pub async fn payouts_create_core(
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
req: payouts::PayoutCreateRequest,
) -> RouterResponse<payouts::PayoutCreateResponse>
where
{
) -> RouterResponse<payouts::PayoutCreateResponse> {
// Form connector data
let connector_data = get_connector_data(
&state,
@ -111,7 +110,7 @@ where
.await?;
// Validate create request
let (payout_id, payout_method_data) =
let (payout_id, payout_method_data, profile_id) =
validator::validate_create_request(&state, &merchant_account, &req, &key_store).await?;
// Create DB entries
@ -121,6 +120,7 @@ where
&key_store,
&req,
&payout_id,
&profile_id,
&connector_data.connector_name,
payout_method_data.as_ref(),
)
@ -561,18 +561,8 @@ pub async fn create_recipient(
let customer_details = payout_data.customer_details.to_owned();
let connector_name = connector_data.connector_name.to_string();
let profile_id = core_utils::get_profile_id_from_business_details(
payout_data.payout_attempt.business_country,
payout_data.payout_attempt.business_label.as_ref(),
merchant_account,
payout_data.payout_attempt.profile_id.as_ref(),
&*state.store,
false,
)
.await?;
// Create the connector label using {profile_id}_{connector_name}
let connector_label = format!("{profile_id}_{}", connector_name);
let connector_label = format!("{}_{}", payout_data.profile_id, connector_name);
let (should_call_connector, _connector_customer_id) =
helpers::should_call_payout_connector_create_customer(
@ -1124,6 +1114,7 @@ pub async fn response_handler(
}
// DB entries
#[allow(clippy::too_many_arguments)]
#[cfg(feature = "payouts")]
pub async fn payout_create_db_entries(
state: &AppState,
@ -1131,6 +1122,7 @@ pub async fn payout_create_db_entries(
key_store: &domain::MerchantKeyStore,
req: &payouts::PayoutCreateRequest,
payout_id: &String,
profile_id: &String,
connector_name: &api_enums::PayoutConnectors,
stored_payout_method_data: Option<&payouts::PayoutMethodData>,
) -> RouterResult<PayoutData> {
@ -1231,8 +1223,7 @@ pub async fn payout_create_db_entries(
} else {
storage_enums::PayoutStatus::RequiresPayoutMethodData
};
let _id = core_utils::get_or_generate_uuid("payout_attempt_id", None)?;
let payout_attempt_id = format!("{}_{}", merchant_id.to_owned(), payout_id.to_owned());
let payout_attempt_id = utils::get_payment_attempt_id(payout_id, 1);
let payout_attempt_req = storage::PayoutAttemptNew::default()
.set_payout_attempt_id(payout_attempt_id.to_string())
@ -1247,7 +1238,7 @@ pub async fn payout_create_db_entries(
.set_payout_token(req.payout_token.to_owned())
.set_created_at(Some(common_utils::date_time::now()))
.set_last_modified_at(Some(common_utils::date_time::now()))
.set_profile_id(req.profile_id.to_owned())
.set_profile_id(Some(profile_id.to_string()))
.to_owned();
let payout_attempt = db
.insert_payout_attempt(payout_attempt_req)
@ -1269,6 +1260,7 @@ pub async fn payout_create_db_entries(
.cloned()
.or(stored_payout_method_data.cloned()),
merchant_connector_account: None,
profile_id: profile_id.to_owned(),
})
}
@ -1318,6 +1310,8 @@ pub async fn make_payout_data(
.await
.map_or(None, |c| c);
let profile_id = payout_attempt.profile_id.clone();
Ok(PayoutData {
billing_address,
customer_details,
@ -1325,5 +1319,6 @@ pub async fn make_payout_data(
payout_attempt,
payout_method_data: None,
merchant_connector_account: None,
profile_id,
})
}

View File

@ -8,7 +8,6 @@ use crate::{
utils as core_utils,
},
db::StorageInterface,
logger,
routes::AppState,
types::{api::payouts, domain, storage},
utils,
@ -24,8 +23,6 @@ pub async fn validate_uniqueness_of_payout_id_against_merchant_id(
let payout = db
.find_payout_by_merchant_id_payout_id(merchant_id, payout_id)
.await;
logger::debug!(?payout);
match payout {
Err(err) => {
if err.current_context().is_db_not_found() {
@ -58,7 +55,7 @@ pub async fn validate_create_request(
merchant_account: &domain::MerchantAccount,
req: &payouts::PayoutCreateRequest,
merchant_key_store: &domain::MerchantKeyStore,
) -> RouterResult<(String, Option<payouts::PayoutMethodData>)> {
) -> RouterResult<(String, Option<payouts::PayoutMethodData>, String)> {
let merchant_id = &merchant_account.merchant_id;
// Merchant ID
@ -111,5 +108,16 @@ pub async fn validate_create_request(
None => None,
};
Ok((payout_id, payout_method_data))
// Profile ID
let profile_id = core_utils::get_profile_id_from_business_details(
req.business_country,
req.business_label.as_ref(),
merchant_account,
req.profile_id.as_ref(),
&*state.store,
false,
)
.await?;
Ok((payout_id, payout_method_data, profile_id))
}

View File

@ -48,33 +48,21 @@ pub async fn get_mca_for_payout<'a>(
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
payout_data: &PayoutData,
) -> RouterResult<(helpers::MerchantConnectorAccountType, String)> {
let payout_attempt = &payout_data.payout_attempt;
let profile_id = get_profile_id_from_business_details(
payout_attempt.business_country,
payout_attempt.business_label.as_ref(),
merchant_account,
payout_attempt.profile_id.as_ref(),
&*state.store,
false,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("profile_id is not set in payout_attempt")?;
) -> RouterResult<helpers::MerchantConnectorAccountType> {
match payout_data.merchant_connector_account.to_owned() {
Some(mca) => Ok((mca, profile_id)),
Some(mca) => Ok(mca),
None => {
let merchant_connector_account = helpers::get_merchant_connector_account(
state,
merchant_account.merchant_id.as_str(),
None,
key_store,
&profile_id,
&payout_data.profile_id,
connector_id,
payout_attempt.merchant_connector_id.as_ref(),
payout_data.payout_attempt.merchant_connector_id.as_ref(),
)
.await?;
Ok((merchant_connector_account, profile_id))
Ok(merchant_connector_account)
}
}
}
@ -89,7 +77,7 @@ pub async fn construct_payout_router_data<'a, F>(
_request: &api_models::payouts::PayoutRequest,
payout_data: &mut PayoutData,
) -> RouterResult<types::PayoutsRouterData<F>> {
let (merchant_connector_account, profile_id) = get_mca_for_payout(
let merchant_connector_account = get_mca_for_payout(
state,
connector_id,
merchant_account,
@ -135,7 +123,7 @@ pub async fn construct_payout_router_data<'a, F>(
let payouts = &payout_data.payouts;
let payout_attempt = &payout_data.payout_attempt;
let customer_details = &payout_data.customer_details;
let connector_label = format!("{profile_id}_{}", payout_attempt.connector);
let connector_label = format!("{}_{}", payout_data.profile_id, payout_attempt.connector);
let connector_customer_id = customer_details
.as_ref()
.and_then(|c| c.connector_customer.as_ref())

View File

@ -0,0 +1,4 @@
ALTER TABLE
payout_attempt
ALTER COLUMN
profile_id DROP NOT NULL;

View File

@ -0,0 +1,6 @@
ALTER TABLE
payout_attempt
ALTER COLUMN
profile_id
SET
NOT NULL;

View File

@ -10570,7 +10570,8 @@
"entity_type",
"status",
"error_message",
"error_code"
"error_code",
"profile_id"
],
"properties": {
"payout_id": {
@ -10702,8 +10703,7 @@
},
"profile_id": {
"type": "string",
"description": "The business profile that is associated with this payment",
"nullable": true
"description": "The business profile that is associated with this payment"
}
}
},

View File

@ -39,6 +39,11 @@
"key": "refund_id",
"value": ""
},
{
"key": "payout_id",
"value": "",
"type": "string"
},
{
"key": "merchant_connector_id",
"value": ""
@ -90,6 +95,16 @@
"key": "connector_api_secret",
"value": "",
"type": "string"
},
{
"key": "payment_profile_id",
"value": "",
"type": "string"
},
{
"key": "payout_profile_id",
"value": "",
"type": "string"
}
]
}

View File

@ -8,14 +8,17 @@
"Scenario6-Create 3DS payment",
"Scenario7-Create 3DS payment with confrm false",
"Scenario9-Refund full payment",
"Scenario10-Partial refund",
"Scenario11-Create a mandate and recurring payment",
"Scenario11-Refund recurring payment",
"Scenario16-Bank Redirect-sofort",
"Scenario17-Bank Redirect-eps",
"Scenario18-Bank Redirect-giropay",
"Scenario19-Bank Redirect-Trustly",
"Scenario19-Bank debit-ach",
"Scenario19-Bank debit-Bacs"
"Scenario10-Create a mandate and recurring payment",
"Scenario11-Partial refund",
"Scenario12-Bank Redirect-sofort",
"Scenario13-Bank Redirect-eps",
"Scenario14-Refund recurring payment",
"Scenario15-Bank Redirect-giropay",
"Scenario16-Bank debit-ach",
"Scenario17-Bank debit-Bacs",
"Scenario18-Bank Redirect-Trustly",
"Scenario19-Add card flow",
"Scenario20-Pass Invalid CVV for save card flow and verify failed payment",
"Scenario21-Don't Pass CVV for save card flow and verify failed payment Copy"
]
}

View File

@ -3,9 +3,12 @@
"Merchant Account - Create",
"API Key - Create",
"Payment Connector - Create",
"Payout Connector - Create",
"Payments - Create",
"Payments - Retrieve",
"Refunds - Create",
"Refunds - Retrieve"
"Refunds - Retrieve",
"Payouts - Create",
"Payouts - Retrieve"
]
}

View File

@ -45,6 +45,10 @@
{
"country": "US",
"business": "default"
},
{
"country": "GB",
"business": "payouts"
}
],
"merchant_details": {

View File

@ -37,3 +37,16 @@ if (jsonData?.merchant_connector_id) {
"INFO - Unable to assign variable {{merchant_connector_id}}, as jsonData.merchant_connector_id is undefined.",
);
}
// pm.collectionVariables - Set profile_id as variable for jsonData.payment_profile_id
if (jsonData?.profile_id) {
pm.collectionVariables.set("payment_profile_id", jsonData.profile_id);
console.log(
"- use {{payment_profile_id}} as collection variable for value",
jsonData.profile_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_profile_id}}, as jsonData.profile_id is undefined.",
);
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,52 @@
// Validate status 2xx
pm.test(
"[POST]::/account/:account_id/connectors - Status code is 2xx",
function () {
pm.response.to.be.success;
},
);
// Validate if response header has matching content-type
pm.test(
"[POST]::/account/:account_id/connectors - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set merchant_connector_id as variable for jsonData.merchant_connector_id
if (jsonData?.merchant_connector_id) {
pm.collectionVariables.set(
"merchant_connector_id",
jsonData.merchant_connector_id,
);
console.log(
"- use {{merchant_connector_id}} as collection variable for value",
jsonData.merchant_connector_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{merchant_connector_id}}, as jsonData.merchant_connector_id is undefined.",
);
}
// pm.collectionVariables - Set profile_id as variable for jsonData.payout_profile_id
if (jsonData?.profile_id) {
pm.collectionVariables.set("payout_profile_id", jsonData.profile_id);
console.log(
"- use {{payout_profile_id}} as collection variable for value",
jsonData.profile_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_profile_id}}, as jsonData.profile_id is undefined.",
);
}

View File

@ -0,0 +1,293 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{admin_api_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"connector_type": "payout_processor",
"connector_name": "adyen",
"connector_account_details": {
"auth_type": "SignatureKey",
"api_key": "{{connector_api_key}}",
"key1": "{{connector_key1}}",
"api_secret": "{{connector_api_secret}}"
},
"test_mode": false,
"disabled": false,
"business_country": "GB",
"business_label": "payouts",
"payment_methods_enabled": [
{
"payment_method": "card",
"payment_method_types": [
{
"payment_method_type": "credit",
"card_networks": ["Visa", "Mastercard"],
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "debit",
"card_networks": ["Visa", "Mastercard"],
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "pay_later",
"payment_method_types": [
{
"payment_method_type": "klarna",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "affirm",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "afterpay_clearpay",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "pay_bright",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "walley",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "wallet",
"payment_method_types": [
{
"payment_method_type": "paypal",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "google_pay",
"payment_experience": "invoke_sdk_client",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "apple_pay",
"payment_experience": "invoke_sdk_client",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "mobile_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "ali_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "we_chat_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "mb_way",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "bank_redirect",
"payment_method_types": [
{
"payment_method_type": "giropay",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "eps",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "sofort",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "blik",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "trustly",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_czech_republic",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_finland",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_poland",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_slovakia",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "bancontact_card",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "bank_debit",
"payment_method_types": [
{
"payment_method_type": "ach",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "bacs",
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
}
]
}
},
"url": {
"raw": "{{baseUrl}}/account/:account_id/connectors",
"host": ["{{baseUrl}}"],
"path": ["account", ":account_id", "connectors"],
"variable": [
{
"key": "account_id",
"value": "{{merchant_id}}",
"description": "(Required) The unique identifier for the merchant account"
}
]
},
"description": "Create a new Payment Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialised services like Fraud / Accounting etc."
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,60 @@
// Validate status 2xx
pm.test("[POST]::/payouts/create - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test(
"[POST]::/payouts/create - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Validate if status is successful
// if (jsonData?.status) {
// pm.test("[POST]::/payouts/create - Content check if value for 'status' matches 'success'",
// function () {
// pm.expect(jsonData.status).to.eql("success");
// },
// );
// }
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) { }
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,72 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 1,
"currency": "EUR",
"customer_id": "payout_customer",
"email": "payout_customer@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payout request",
"connector": ["adyen"],
"payout_type": "bank",
"payout_method_data": {
"bank": {
"iban": "NL46TEST0136169112",
"bic": "ABNANL2A",
"bank_name": "Deutsche Bank",
"bank_country_code": "NL",
"bank_city": "Amsterdam"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"entity_type": "Individual",
"recurring": true,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js"]
}

View File

@ -0,0 +1,48 @@
// Validate status 2xx
pm.test("[GET]::/payouts/:id - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[GET]::/payouts/:id - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// Validate if response has JSON Body
pm.test("[GET]::/payouts/:id - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,22 @@
{
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
}
],
"url": {
"raw": "{{baseUrl}}/payouts/:id",
"host": ["{{baseUrl}}"],
"path": ["payouts", ":id"],
"variable": [
{
"key": "id",
"value": "{{payout_id}}",
"description": "(Required) unique payment id"
}
]
},
"description": "To retrieve the properties of a Payment. This may be used to get the status of a previously initiated payment or next action for an ongoing payment"
}

View File

@ -8,6 +8,7 @@
"Scenario6-Create 3DS payment with greater capture",
"Scenario7-Refund exceeds amount",
"Scenario8-Refund for unsuccessful payment",
"Scenario9-Create a recurring payment with greater mandate amount"
"Scenario9-Create a recurring payment with greater mandate amount",
"Scenario10-Create payouts using unsupported methods"
]
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["ACH Payouts - Create", "Bacs Payouts - Create"]
}

View File

@ -0,0 +1,48 @@
// Validate status 4xx
pm.test("[POST]::/payouts/create - Status code is 4xx", function () {
pm.response.to.be.clientError;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,99 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 10000,
"currency": "USD",
"customer_id": "payout_customer",
"email": "payout_customer@example.com",
"name": "Doest John",
"phone": "6168205366",
"phone_country_code": "+1",
"description": "Its my first payout request",
"connector": ["adyen"],
"payout_type": "bank",
"payout_method_data": {
"bank": {
"bank_routing_number": "110000000",
"bank_account_number": "000123456789",
"bank_name": "Stripe Test Bank",
"bank_country_code": "US",
"bank_city": "California"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "Doest",
"last_name": "John"
},
"phone": {
"number": "6168205366",
"country_code": "1"
}
},
"entity_type": "Individual",
"recurring": false,
"metadata": {
"ref": "123",
"vendor_details": {
"account_type": "custom",
"business_type": "individual",
"business_profile_mcc": 5045,
"business_profile_url": "https://www.pastebin.com",
"business_profile_name": "pT",
"company_address_line1": "address_full_match",
"company_address_line2": "Kimberly Way",
"company_address_postal_code": "31062",
"company_address_city": "Milledgeville",
"company_address_state": "GA",
"company_phone": "+16168205366",
"company_tax_id": "000000000",
"company_owners_provided": false,
"capabilities_card_payments": true,
"capabilities_transfers": true
},
"individual_details": {
"tos_acceptance_date": 1680581051,
"tos_acceptance_ip": "103.159.11.202",
"individual_dob_day": "01",
"individual_dob_month": "01",
"individual_dob_year": "1901",
"individual_id_number": "000000000",
"individual_ssn_last_4": "0000",
"external_account_account_holder_type": "individual"
}
},
"confirm": true,
"auto_fulfill": true
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,48 @@
// Validate status 4xx
pm.test("[POST]::/payouts/create - Status code is 4xx", function () {
pm.response.to.be.clientError;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,74 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 1,
"currency": "GBP",
"customer_id": "payout_customer",
"email": "payout_customer@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payout request",
"payout_type": "bank",
"payout_method_data": {
"bank": {
"bank_sort_code": "231470",
"bank_account_number": "28821822",
"bank_name": "Deutsche Bank",
"bank_country_code": "NL",
"bank_city": "Amsterdam"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"entity_type": "Individual",
"recurring": true,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true,
"connector": ["adyen"],
"business_label": "abcd",
"business_country": "US"
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,35 @@
// Add appropriate profile_id for relevant requests
const path = pm.request.url.toString();
const isPostRequest = pm.request.method.toString() === "POST";
const isPaymentCreation = path.match(/\/payments$/) && isPostRequest;
const isPayoutCreation = path.match(/\/payouts\/create$/) && isPostRequest;
if (isPaymentCreation || isPayoutCreation) {
try {
const request = JSON.parse(pm.request.body.toJSON().raw);
// Attach profile_id
const profile_id = isPaymentCreation
? pm.collectionVariables.get("payment_profile_id")
: pm.collectionVariables.get("payout_profile_id");
request["profile_id"] = profile_id;
// Attach routing
const routing = { type: "single", data: "adyen" };
request["routing"] = routing;
let updatedRequest = {
mode: "raw",
raw: JSON.stringify(request),
options: {
raw: {
language: "json",
},
},
};
pm.request.body.update(updatedRequest);
} catch (error) {
console.error("Failed to inject profile_id in the request");
console.error(error);
}
}

View File

@ -0,0 +1,22 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{api_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.prerequest.js", "event.test.js"]
}

View File

@ -0,0 +1,8 @@
{
"info": {
"_postman_id": "b5107328-6e3c-4ef0-b575-4072bc64462a",
"name": "wise",
"description": "## Get started\n\nJuspay Router provides a collection of APIs that enable you to process and manage payments. Our APIs accept and return JSON in the HTTP body, and return standard HTTP response codes. \nYou can consume the APIs directly using your favorite HTTP/REST library. \nWe have a testing environment referred to \"sandbox\", which you can setup to test API calls without affecting production data.\n\n### Base URLs\n\nUse the following base URLs when making requests to the APIs:\n\n| Environment | Base URL |\n| --- | --- |\n| Sandbox | [https://sandbox.hyperswitch.io](https://sandbox.hyperswitch.io) |\n| Production | [https://router.juspay.io](https://router.juspay.io) |\n\n# Authentication\n\nWhen you sign up for an account, you are given a secret key (also referred as api-key). You may authenticate all API requests with Juspay server by providing the appropriate key in the request Authorization header. \nNever share your secret api keys. Keep them guarded and secure.\n\nContact Support: \nName: Juspay Support \nEmail: [support@juspay.in](mailto:support@juspay.in)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
}
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Health check", "Flow Testcases"]
}

View File

@ -0,0 +1,100 @@
{
"variable": [
{
"key": "baseUrl",
"value": "",
"type": "string"
},
{
"key": "admin_api_key",
"value": "",
"type": "string"
},
{
"key": "api_key",
"value": "",
"type": "string"
},
{
"key": "merchant_id",
"value": ""
},
{
"key": "payment_id",
"value": ""
},
{
"key": "customer_id",
"value": ""
},
{
"key": "mandate_id",
"value": ""
},
{
"key": "payment_method_id",
"value": ""
},
{
"key": "refund_id",
"value": ""
},
{
"key": "payout_id",
"value": "",
"type": "string"
},
{
"key": "merchant_connector_id",
"value": ""
},
{
"key": "client_secret",
"value": "",
"type": "string"
},
{
"key": "connector_api_key",
"value": "",
"type": "string"
},
{
"key": "connector_key1",
"value": ""
},
{
"key": "publishable_key",
"value": "",
"type": "string"
},
{
"key": "payment_token",
"value": "",
"type": "string"
},
{
"key": "gateway_merchant_id",
"value": "",
"type": "string"
},
{
"key": "certificate",
"value": "",
"type": "string"
},
{
"key": "certificate_keys",
"value": "",
"type": "string"
},
{
"key": "api_key_id",
"value": ""
},
{
"key": "connector_api_secret",
"value": "",
"type": "string"
}
]
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["QuickStart", "Happy Cases", "Variation Cases"]
}

View File

@ -0,0 +1,6 @@
{
"childrenOrder": [
"Scenario1 - Process Bacs Payout",
"Scenario2 - Process SEPA Payout"
]
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Payouts - Create"]
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,48 @@
// Validate status 2xx
pm.test("[POST]::/payouts/create - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,72 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 1,
"currency": "GBP",
"customer_id": "wise_customer",
"email": "payout_customer@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payout request",
"payout_type": "bank",
"payout_method_data": {
"bank": {
"bank_sort_code": "231470",
"bank_account_number": "28821822",
"bank_name": "Deutsche Bank",
"bank_country_code": "NL",
"bank_city": "Amsterdam"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"entity_type": "Individual",
"recurring": true,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true,
"connector": ["wise"]
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Payouts - Create"]
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,48 @@
// Validate status 2xx
pm.test("[POST]::/payouts/create - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,72 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 1,
"currency": "EUR",
"customer_id": "wise_customer",
"email": "payout_customer@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payout request",
"connector": ["wise"],
"payout_type": "bank",
"payout_method_data": {
"bank": {
"iban": "NL46TEST0136169112",
"bic": "ABNANL2A",
"bank_name": "Deutsche Bank",
"bank_country_code": "NL",
"bank_city": "Amsterdam"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"entity_type": "Individual",
"recurring": true,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,8 @@
{
"childrenOrder": [
"Merchant Account - Create",
"API Key - Create",
"Payout Connector - Create",
"Payouts - Create"
]
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js"]
}

View File

@ -0,0 +1,46 @@
// Validate status 2xx
pm.test("[POST]::/api_keys/:merchant_id - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test(
"[POST]::/api_keys/:merchant_id - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set api_key_id as variable for jsonData.key_id
if (jsonData?.key_id) {
pm.collectionVariables.set("api_key_id", jsonData.key_id);
console.log(
"- use {{api_key_id}} as collection variable for value",
jsonData.key_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{api_key_id}}, as jsonData.key_id is undefined.",
);
}
// pm.collectionVariables - Set api_key as variable for jsonData.api_key
if (jsonData?.api_key) {
pm.collectionVariables.set("api_key", jsonData.api_key);
console.log(
"- use {{api_key}} as collection variable for value",
jsonData.api_key,
);
} else {
console.log(
"INFO - Unable to assign variable {{api_key}}, as jsonData.api_key is undefined.",
);
}

View File

@ -0,0 +1,47 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{admin_api_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
}
]
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw_json_formatted": {
"name": "API Key 1",
"description": null,
"expiration": "2069-09-23T01:02:03.000Z"
}
},
"url": {
"raw": "{{baseUrl}}/api_keys/:merchant_id",
"host": ["{{baseUrl}}"],
"path": ["api_keys", ":merchant_id"],
"variable": [
{
"key": "merchant_id",
"value": "{{merchant_id}}"
}
]
}
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,56 @@
// Validate status 2xx
pm.test("[POST]::/accounts - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/accounts - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set merchant_id as variable for jsonData.merchant_id
if (jsonData?.merchant_id) {
pm.collectionVariables.set("merchant_id", jsonData.merchant_id);
console.log(
"- use {{merchant_id}} as collection variable for value",
jsonData.merchant_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{merchant_id}}, as jsonData.merchant_id is undefined.",
);
}
// pm.collectionVariables - Set api_key as variable for jsonData.api_key
if (jsonData?.api_key) {
pm.collectionVariables.set("api_key", jsonData.api_key);
console.log(
"- use {{api_key}} as collection variable for value",
jsonData.api_key,
);
} else {
console.log(
"INFO - Unable to assign variable {{api_key}}, as jsonData.api_key is undefined.",
);
}
// pm.collectionVariables - Set publishable_key as variable for jsonData.publishable_key
if (jsonData?.publishable_key) {
pm.collectionVariables.set("publishable_key", jsonData.publishable_key);
console.log(
"- use {{publishable_key}} as collection variable for value",
jsonData.publishable_key,
);
} else {
console.log(
"INFO - Unable to assign variable {{publishable_key}}, as jsonData.publishable_key is undefined.",
);
}

View File

@ -0,0 +1,91 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{admin_api_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"merchant_id": "postman_merchant_GHAction_{{$guid}}",
"locker_id": "m0010",
"merchant_name": "NewAge Retailer",
"primary_business_details": [
{
"country": "US",
"business": "default"
}
],
"merchant_details": {
"primary_contact_person": "John Test",
"primary_email": "JohnTest@test.com",
"primary_phone": "sunt laborum",
"secondary_contact_person": "John Test2",
"secondary_email": "JohnTest2@test.com",
"secondary_phone": "cillum do dolor id",
"website": "www.example.com",
"about_business": "Online Retail with a wide selection of organic products for North America",
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US"
}
},
"return_url": "https://duck.com",
"webhook_details": {
"webhook_version": "1.0.1",
"webhook_username": "ekart_retail",
"webhook_password": "password_ekart@123",
"payment_created_enabled": true,
"payment_succeeded_enabled": true,
"payment_failed_enabled": true
},
"sub_merchants_enabled": false,
"metadata": {
"city": "NY",
"unit": "245"
}
}
},
"url": {
"raw": "{{baseUrl}}/accounts",
"host": ["{{baseUrl}}"],
"path": ["accounts"]
},
"description": "Create a new account for a merchant. The merchant could be a seller or retailer or client who likes to receive and send payments."
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,39 @@
// Validate status 2xx
pm.test(
"[POST]::/account/:account_id/connectors - Status code is 2xx",
function () {
pm.response.to.be.success;
},
);
// Validate if response header has matching content-type
pm.test(
"[POST]::/account/:account_id/connectors - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set merchant_connector_id as variable for jsonData.merchant_connector_id
if (jsonData?.merchant_connector_id) {
pm.collectionVariables.set(
"merchant_connector_id",
jsonData.merchant_connector_id,
);
console.log(
"- use {{merchant_connector_id}} as collection variable for value",
jsonData.merchant_connector_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{merchant_connector_id}}, as jsonData.merchant_connector_id is undefined.",
);
}

View File

@ -0,0 +1,333 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{admin_api_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"connector_type": "payout_processor",
"connector_name": "wise",
"connector_account_details": {
"auth_type": "BodyKey",
"api_key": "{{connector_api_key}}",
"key1": "{{connector_key1}}"
},
"test_mode": false,
"disabled": false,
"business_country": "US",
"business_label": "default",
"payment_methods_enabled": [
{
"payment_method": "card",
"payment_method_types": [
{
"payment_method_type": "credit",
"card_networks": ["Visa", "Mastercard"],
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "debit",
"card_networks": ["Visa", "Mastercard"],
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "pay_later",
"payment_method_types": [
{
"payment_method_type": "klarna",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "affirm",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "afterpay_clearpay",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "pay_bright",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "walley",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "wallet",
"payment_method_types": [
{
"payment_method_type": "paypal",
"payment_experience": "redirect_to_url",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "google_pay",
"payment_experience": "invoke_sdk_client",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "apple_pay",
"payment_experience": "invoke_sdk_client",
"card_networks": null,
"accepted_currencies": null,
"accepted_countries": null,
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "mobile_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "ali_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "we_chat_pay",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "mb_way",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "bank_redirect",
"payment_method_types": [
{
"payment_method_type": "giropay",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "eps",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "sofort",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "blik",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "trustly",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_czech_republic",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_finland",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_poland",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "online_banking_slovakia",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "bancontact_card",
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
},
{
"payment_method": "bank_debit",
"payment_method_types": [
{
"payment_method_type": "ach",
"recurring_enabled": true,
"installment_payment_enabled": true
},
{
"payment_method_type": "bacs",
"recurring_enabled": true,
"installment_payment_enabled": true
}
]
}
],
"metadata": {
"google_pay": {
"allowed_payment_methods": [
{
"type": "CARD",
"parameters": {
"allowed_auth_methods": ["PAN_ONLY", "CRYPTOGRAM_3DS"],
"allowed_card_networks": [
"AMEX",
"DISCOVER",
"INTERAC",
"JCB",
"MASTERCARD",
"VISA"
]
},
"tokenization_specification": {
"type": "PAYMENT_GATEWAY"
}
}
],
"merchant_info": {
"merchant_name": "Narayan Bhat"
}
},
"apple_pay": {
"session_token_data": {
"initiative": "web",
"certificate": "{{certificate}}",
"display_name": "applepay",
"certificate_keys": "{{certificate_keys}}",
"initiative_context": "hyperswitch-sdk-test.netlify.app",
"merchant_identifier": "merchant.com.stripe.sang"
},
"payment_request_data": {
"label": "applepay pvt.ltd",
"supported_networks": ["visa", "masterCard", "amex", "discover"],
"merchant_capabilities": ["supports3DS"]
}
}
}
}
},
"url": {
"raw": "{{baseUrl}}/account/:account_id/connectors",
"host": ["{{baseUrl}}"],
"path": ["account", ":account_id", "connectors"],
"variable": [
{
"key": "account_id",
"value": "{{merchant_id}}",
"description": "(Required) The unique identifier for the merchant account"
}
]
},
"description": "Create a new Payment Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialised services like Fraud / Accounting etc."
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,48 @@
// Validate status 2xx
pm.test("[POST]::/payouts/create - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,72 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 1,
"currency": "EUR",
"customer_id": "wise_customer",
"email": "payout_customer@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payout request",
"connector": ["wise"],
"payout_type": "bank",
"payout_method_data": {
"bank": {
"iban": "NL46TEST0136169112",
"bic": "ABNANL2A",
"bank_name": "Deutsche Bank",
"bank_country_code": "NL",
"bank_city": "Amsterdam"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"entity_type": "Individual",
"recurring": true,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Scenario1 - Create ACH payout with invalid data"]
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Payouts - Create"]
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js", "event.prerequest.js"]
}

View File

@ -0,0 +1,48 @@
// Validate status 4xx
pm.test("[POST]::/payouts/create - Status code is 4xx", function () {
pm.response.to.be.clientError;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payouts/create - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payouts/create - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payout_id as variable for jsonData.payout_id
if (jsonData?.payout_id) {
pm.collectionVariables.set("payout_id", jsonData.payout_id);
console.log(
"- use {{payout_id}} as collection variable for value",
jsonData.payout_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payout_id}}, as jsonData.payout_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}

View File

@ -0,0 +1,72 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 10000,
"currency": "USD",
"customer_id": "wise_customer",
"email": "payout_customer@example.com",
"name": "Doest John",
"phone": "6168205366",
"phone_country_code": "+1",
"description": "Its my first payout request",
"connector": ["wise"],
"payout_type": "bank",
"payout_method_data": {
"bank": {
"bank_routing_number": "110000000",
"bank_account_number": "000123456789",
"bank_name": "Stripe Test Bank",
"bank_country_code": "US",
"bank_city": "California"
}
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "CA",
"zip": "94122",
"country": "US",
"first_name": "Doest",
"last_name": "John"
},
"phone": {
"number": "6168205366",
"country_code": "1"
}
},
"entity_type": "Individual",
"recurring": false,
"metadata": {
"ref": "123"
},
"confirm": true,
"auto_fulfill": true
}
},
"url": {
"raw": "{{baseUrl}}/payouts/create",
"host": ["{{baseUrl}}"],
"path": ["payouts", "create"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,3 @@
{
"childrenOrder": ["Health"]
}

View File

@ -0,0 +1,3 @@
{
"eventOrder": ["event.test.js"]
}

View File

@ -0,0 +1,4 @@
// Validate status 2xx
pm.test("[POST]::/accounts - Status code is 2xx", function () {
pm.response.to.be.success;
});

View File

@ -0,0 +1,16 @@
{
"method": "GET",
"header": [
{
"key": "x-feature",
"value": "router-custom",
"type": "text",
"disabled": true
}
],
"url": {
"raw": "{{baseUrl}}/health",
"host": ["{{baseUrl}}"],
"path": ["health"]
}
}

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,13 @@
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log("[LOG]::payment_id - " + jsonData.payment_id);
}
console.log("[LOG]::x-request-id - " + pm.response.headers.get("x-request-id"));