Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(FRM): Revise post FRM core flows #4394

Merged
merged 28 commits into from Apr 29, 2024
Merged

feat(FRM): Revise post FRM core flows #4394

merged 28 commits into from Apr 29, 2024

Conversation

srujanchikke
Copy link
Contributor

@srujanchikke srujanchikke commented Apr 18, 2024

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

PostAuth flow

  • The underlying FRM connector is invoked post authentication of the user from the bank.
  • If a transaction’s capture method was set to automatic, it is updated to manual for avoiding automatic capture.
  • Once the user completes the authentication, the underlying FRM connector is invoked. The decision whether or not to
    proceed with the txn is based on the status / score returned.

Possible actions based on the status

  • Continue on Accept
    - Continue with the transaction
  • Halt on Decline
    - Mark the transaction as cancelled
  • Approve / Decline on Manual Review
    - Hold the txn in manual review state. Merchants can list and review such transactions.
    - If approved, payment is captured
    - If declined, payment is voided

This flow works same as payments flow incase of 3ds, non 3ds, manual and auto capture for Legit payments.

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

up.sql

ALTER TABLE fraud_check 
ADD COLUMN IF NOT EXISTS payment_capture_method "CaptureMethod" NULL;

down.sql

ALTER TABLE fraud_check 
DROP COLUMN IF EXISTS payment_capture_method;

Motivation and Context

How did you test it?

Create merchant connector account with stripe and then create new merchant connector account with signifyd.

{
  "connector_type": "payment_VAS",
  "connector_name": "signifyd",
  "connector_account_details": {
    "auth_type": "HeaderKey",
    "api_key": "YOUR_API_KEY"
  },
  "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",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        },
        {
          "payment_method_type": "affirm",
          "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        },
        {
          "payment_method_type": "afterpay_clearpay",
          "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        }
      ]
    }
  ],
  "metadata": {
    "city": "NY",
    "unit": "245"
  },
  "frm_configs": [
        {
            "gateway": "stripe",
            "payment_methods": [
                {
                    "payment_method": "card",
                    "payment_method_types": [
                        {
                            "payment_method_type": "credit",
                            "card_networks": [
                                "Visa"
                            ],
                            "flow": "post",
                            "action": "cancel_txn"
                        },
                        {
                            "payment_method_type": "debit",
                            "card_networks": [
                                "Visa"
                            ],
                            "flow": "post",
                            "action": "manual_review"
                        }
                    ]
                }
            ]
        }
    ]
}

TEST CASE 1 : Create legit card payment(amount =150) for both credit and debit. This should go as normal payment flow. Interchange CaptureMethod and CardType(3ds, non 3ds).
TEST CASE 2 : Create Credit(pmt type) Payment with amount equals to 15000. This should Fail the payment .

{
  "amount": 15000,
  "currency": "USD",
  "confirm": true,
  "capture_method": "manual",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 1500,
  "customer_id": "StripeCustomer2",
  "email": "guest@example.com",
  "name": "Bob Smith",
  "phone": "999999999",
  "phone_country_code": "+91",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "payment_method": "card",
  "payment_method_type": "credit",
  "payment_method_data": {
    "card": {
      "card_number": "4242424242424242",
      "card_exp_month": "10",
      "card_exp_year": "25",
      "card_holder_name": "joseph Doe",
      "card_cvc": "123"
    }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "31 Sherwood Gardens",
      "line3": "31 Sherwood Gardens",
      "city": "London",
      "state": "Manchester",
      "zip": "E14 9wn",
      "country": "GB",
      "first_name": "Bob",
      "last_name": "Smith"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  },
  "order_details" : [{
        "product_name" : "gillete creme",
        "quantity" : 2,
        "amount" : 600
    },
    {
        "product_name" : "gillete razor",
        "quantity" : 1,
        "amount" : 300
    }]
}

TESTCASE 3 : Create a payment with payment method type as debit. set capture method to automatic and use same json above. Payment status should be moved to RequiresMerchantAction.
Response looks like this

{
    "payment_id": "pay_9ZgUMXOiLv35wrF6oOyd",
    "merchant_id": "merchant_1713525778",
    "status": "requires_merchant_action",
    "amount": 150000,
    "net_amount": 150000,
    "amount_capturable": 150000,
    "amount_received": 0,
    "connector": "stripe",
    "client_secret": "pay_9ZgUMXOiLv35wrF6oOyd_secret_wU5hfAMsYjBe0fXepJmj",
    "created": "2024-04-19T11:58:40.749Z",
    "currency": "USD",
    "customer_id": "StripeCustomer2",
    "customer": {
        "id": "StripeCustomer2",
        "name": "Bob Smith",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+91"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "manual",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "4242",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "424242",
            "card_extended_bin": "42424242",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "joseph Doe",
            "payment_checks": {
                "cvc_check": "pass",
                "address_line1_check": "pass",
                "address_postal_code_check": "pass"
            },
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "London",
            "country": "GB",
            "line1": "1467",
            "line2": "31 Sherwood Gardens",
            "line3": "31 Sherwood Gardens",
            "zip": "E14 9wn",
            "state": "Manchester",
            "first_name": "Bob",
            "last_name": "Smith"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": [
        {
            "brand": null,
            "amount": 600,
            "category": null,
            "quantity": 2,
            "product_id": null,
            "product_name": "gillete creme",
            "product_type": null,
            "product_img_link": null,
            "requires_shipping": null
        },
        {
            "brand": null,
            "amount": 300,
            "category": null,
            "quantity": 1,
            "product_id": null,
            "product_name": "gillete razor",
            "product_type": null,
            "product_img_link": null,
            "requires_shipping": null
        }
    ],
    "email": "guest@example.com",
    "name": "Bob Smith",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": "fraud",
    "error_message": "Refund Initiated with the processor",
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "StripeCustomer2",
        "created_at": 1713527920,
        "expires": 1713531520,
        "secret": "epk_22d24f1ef64b44a0b28b72a81c2b2392"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "pi_3P7G5VD5R7gDAGff0XEZqQkO",
    "frm_message": {
        "frm_name": "signifyd",
        "frm_transaction_id": "pay_9ZgUMXOiLv35wrF6oOyd_1",
        "frm_transaction_type": "post_frm",
        "frm_status": "fraud",
        "frm_score": 497,
        "frm_reason": "SIGNIFYD_DECLINED",
        "frm_error": null
    },
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pi_3P7G5VD5R7gDAGff0XEZqQkO",
    "payment_link": null,
    "profile_id": "pro_DOE6fPp88zY1M4xUyO0H",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_U0XVEDfTM0JMpiv9GOr5",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-04-19T12:13:40.749Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-04-19T11:58:41.929Z"
}

/approve and /reject should hit after above step for the same payment which will mark payment as succeeded and failed by merchant.

Request curl :

curl --location --request POST 'http://localhost:8080/payments/{{payment_id}}/approve' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key:{{api_key}}' \
--data-raw '{}'

Response json :

{
    "payment_id": "pay_9ZgUMXOiLv35wrF6oOyd",
    "merchant_id": "merchant_1713525778",
    "status": "succeeded",
    "amount": 150000,
    "net_amount": 150000,
    "amount_capturable": 0,
    "amount_received": 150000,
    "connector": "stripe",
    "client_secret": "pay_9ZgUMXOiLv35wrF6oOyd_secret_wU5hfAMsYjBe0fXepJmj",
    "created": "2024-04-19T11:58:40.749Z",
    "currency": "USD",
    "customer_id": "StripeCustomer2",
    "customer": {
        "id": "StripeCustomer2",
        "name": "Bob Smith",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+91"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "manual",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "4242",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "424242",
            "card_extended_bin": "42424242",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "joseph Doe",
            "payment_checks": {
                "cvc_check": "pass",
                "address_line1_check": "pass",
                "address_postal_code_check": "pass"
            },
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "London",
            "country": "GB",
            "line1": "1467",
            "line2": "31 Sherwood Gardens",
            "line3": "31 Sherwood Gardens",
            "zip": "E14 9wn",
            "state": "Manchester",
            "first_name": "Bob",
            "last_name": "Smith"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": [
        {
            "brand": null,
            "amount": 600,
            "category": null,
            "quantity": 2,
            "product_id": null,
            "product_name": "gillete creme",
            "product_type": null,
            "product_img_link": null,
            "requires_shipping": null
        },
        {
            "brand": null,
            "amount": 300,
            "category": null,
            "quantity": 1,
            "product_id": null,
            "product_name": "gillete razor",
            "product_type": null,
            "product_img_link": null,
            "requires_shipping": null
        }
    ],
    "email": "guest@example.com",
    "name": "Bob Smith",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "pi_3P7G5VD5R7gDAGff0XEZqQkO",
    "frm_message": {
        "frm_name": "signifyd",
        "frm_transaction_id": "pay_9ZgUMXOiLv35wrF6oOyd_1",
        "frm_transaction_type": "post_frm",
        "frm_status": "fraud",
        "frm_score": 497,
        "frm_reason": "SIGNIFYD_DECLINED",
        "frm_error": null
    },
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pi_3P7G5VD5R7gDAGff0XEZqQkO",
    "payment_link": null,
    "profile_id": "pro_DOE6fPp88zY1M4xUyO0H",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": "approved",
    "merchant_connector_id": "mca_U0XVEDfTM0JMpiv9GOr5",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-04-19T12:13:40.749Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-04-19T12:01:50.944Z"
}

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible
  • I added a CHANGELOG entry if applicable

@srujanchikke srujanchikke added A-core Area: Core flows A-payments Area: payments labels Apr 18, 2024
@srujanchikke srujanchikke self-assigned this Apr 18, 2024
@srujanchikke srujanchikke changed the title feature(core): Revise post FRM core flows feat(payouts): Revise post FRM core flows Apr 19, 2024
@srujanchikke srujanchikke changed the title feat(payouts): Revise post FRM core flows feat(FRM): Revise post FRM core flows Apr 19, 2024
@srujanchikke srujanchikke linked an issue Apr 19, 2024 that may be closed by this pull request
@srujanchikke srujanchikke marked this pull request as ready for review April 22, 2024 05:08
@srujanchikke srujanchikke requested review from a team as code owners April 22, 2024 05:08
@srujanchikke srujanchikke added the S-waiting-on-review Status: This PR has been implemented and needs to be reviewed label Apr 22, 2024
@srujanchikke srujanchikke requested review from a team as code owners April 24, 2024 10:30
kashif-m
kashif-m previously approved these changes Apr 25, 2024
@@ -25,6 +26,7 @@ pub struct FraudCheck {
pub metadata: Option<serde_json::Value>,
pub modified_at: PrimitiveDateTime,
pub last_step: FraudCheckLastStep,
pub frm_capture_method: Option<storage_enums::CaptureMethod>, // In postFrm, we are updating capture method from automatic to manual. To store the merchant actual capture method, we are storing the actual capture method in frm_capture_method. It will be useful while approving the FRM decision.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have a separate enum for this, just in case we might need to have different enum variants for these

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are using same capture method type as payment capture method, I am just renaming frm_capture_method to payment_capture_method as we discussed.

@@ -1176,6 +1179,7 @@ pub enum IntentStatus {
Processing,
RequiresCustomerAction,
RequiresMerchantAction,
FrmRequiresMerchantAction,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use RequiresMerchantAction, this is meant to indicate that there is some MerhantAction that is required based on the frm message or some additional fields

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Narayanbhat166 , We have introduced this status to not interfere with payments which doesn't go through FRM. In future there might decisions/actions we might take based on FrmRequiredMerchantAction status for FRM webhooks which doesn't apply for payment connectors.

cc: @kashif-m @AnandKGanesh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this status is introduced for explicitly specifying the fact that merchant needs to take an FRM related action on the payment. Using existing variant RequiresMerchantAction does not give enough context about what exactly merchant needs to do. This variant is being used in one of the flows for some crypto connector cc: @srujanchikke

Having a separate variant in this case gives us full context about the type of actions that can be taken by the merchant (payment approval / cancellation in this case)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc : @jarnura

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not introduce the same status RequiresMerchantAction with some prefix again because the merchant wants to do something different by this. If RequiresMerchantAction is the status, then always the merchant should go to some details field or reason field, which tells what is issue and what merchant needs do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add the feasibility to be able to list only the fraudulent transactions in payments list / filter APIs using the details / reason field

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do that it in subsequent PR

crates/router/src/core/fraud_check.rs Show resolved Hide resolved
api_models::enums::AttemptStatus::FrmUnresolved
)
{
payment_data.payment_intent.status = IntentStatus::RequiresCapture; // In Approve flow, payment which has payment_capture_method "manual" and attempt status as "FrmUnresolved",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Payment data update should not happen within frm flow, only pass the suggestion on what to do with the transaction let the payments_core decide whether to consider the frm_suggestion or not. Check the update_trackers of payment_confirm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info, I have added new frmSuggestion and moved this logic to approve->update trackers

) -> RouterResult<Option<FrmData>> {
if matches!(frm_data.fraud_check.frm_status, FraudCheckStatus::Fraud)
&& matches!(frm_configs.frm_action, FrmAction::AutoRefund)
&& matches!(frm_configs.frm_action, FrmAction::CancelTxn)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had three frm configs right?

  1. Pre frm -> Cancel on fraud
  2. Pre frm -> Complete transaction and mark as fraud. merchant will trigger refund if needed
  3. Post frm -> Auto refund on fraud
  4. Post frm -> Authorize the payment and send it for manual review. Cancel or Capture payment based on merchant decision

Why are we removing the 3 option here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Revised flow, We don't actually capture the payment rather we authorize the payments(Post Frm) then take a call whether to cancel/hold/capture . When merchant approves ,we capture the payment or else we cancel the payment.

@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Apr 29, 2024
Merged via the queue into main with commit 01ec7c6 Apr 29, 2024
10 of 12 checks passed
@Gnanasundari24 Gnanasundari24 deleted the frm_core_flows branch April 29, 2024 07:11
@srujanchikke srujanchikke added the M-database-changes Metadata: This PR involves database schema changes label Apr 29, 2024
pixincreate added a commit that referenced this pull request Apr 30, 2024
…to-env

* 'main' of github.com:juspay/hyperswitch:
  Refactor(core): remove payment_method_id from RouterData struct (#4485)
  fix(euclid_wasm): connector config wasm metadata update (#4460)
  chore(version): 2024.04.30.0
  feat(user): add single purpose token and auth (#4470)
  feat: stripe connect integration for payouts (#2041)
  feat(router): handle authorization for frictionless flow in external 3ds flow (#4471)
  feat(FRM): Revise post FRM core flows (#4394)
  feat(router): send poll_config in next_action of confirm response for external 3ds flow (#4443)
  chore(version): 2024.04.29.0
  feat(connector): [CRYPTOPAY]  Report underpaid/overpaid amount in outgoing webhooks (#4468)
  feat(users): use cookie for auth (#4434)
  refactor(scheduler): join frequency and count in `RetryMapping` (#4313)
  refactor(required_fields): change required fields for billing address (#4258)
  refactor(access_token): use `merchant_connector_id` for storing access token (#4462)
  chore(version): 2024.04.26.0
  chore(postman): update Postman collection files
pixincreate added a commit that referenced this pull request Apr 30, 2024
* 'main' of github.com:juspay/hyperswitch:
  refactor(cypress): read creds from env instead of hardcoding the path  (#4430)
  ci: fix paypal postman tests (#4501)
  Refactor(core): remove payment_method_id from RouterData struct (#4485)
  fix(euclid_wasm): connector config wasm metadata update (#4460)
  chore(version): 2024.04.30.0
  feat(user): add single purpose token and auth (#4470)
  feat: stripe connect integration for payouts (#2041)
  feat(router): handle authorization for frictionless flow in external 3ds flow (#4471)
  feat(FRM): Revise post FRM core flows (#4394)
  feat(router): send poll_config in next_action of confirm response for external 3ds flow (#4443)
  chore(version): 2024.04.29.0
  feat(connector): [CRYPTOPAY]  Report underpaid/overpaid amount in outgoing webhooks (#4468)
  feat(users): use cookie for auth (#4434)
  refactor(scheduler): join frequency and count in `RetryMapping` (#4313)
  refactor(required_fields): change required fields for billing address (#4258)
  refactor(access_token): use `merchant_connector_id` for storing access token (#4462)
  chore(version): 2024.04.26.0
  chore(postman): update Postman collection files
@SanchithHegde SanchithHegde removed the S-waiting-on-review Status: This PR has been implemented and needs to be reviewed label May 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Core flows A-payments Area: payments M-database-changes Metadata: This PR involves database schema changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Refactor] PostAuth FRM flow
7 participants