Skip to content

Conversation

@tsdk02
Copy link
Contributor

@tsdk02 tsdk02 commented Jun 3, 2025

Type of Change

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

Description

Summary

This PR enhances the merchant onboarding system by allowing Platform Organizations to onboard and manage Standard Merchant Accounts, in addition to the existing Platform Merchant Account and Connected Merchant Accounts.

Background

Until now, a Platform Organization contained:

  • A single Platform Merchant Account
  • Other accounts as Connected Merchant Accounts

Key Changes

  • Updated merchant account creation logic to allow creating Standard Merchant Accounts in platform organizations
  • Added organization validation when using Fallback API Key for Organization Retrieve and Organization Update APIs.
  • Restricted creation of platform organization under an ENV.

Additional Changes

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

Motivation and Context

To enable maintaining separate standalone merchant accounts in an organization with platform merchant capabilities.

How did you test it?

Create Platform Organization and Platform Merchant:

Request:

curl --location 'http://localhost:8080/user/create_platform' \
--header 'cookie: login_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMzgwZTNiMzAtYzU4Mi00YWU5LTkwZGItYjQ0YTVhYTNlOGVjIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQxNzc5OTIxIiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0OTEwNTE5Mywib3JnX2lkIjoib3JnX2lxdFFoY245YTRZV2owNVp1NENUIiwicHJvZmlsZV9pZCI6InByb19ybEl6aU1XNXhtdFNjOTI3WXRnayIsInRlbmFudF9pZCI6InB1YmxpYyJ9.Tg8EXphM7jV1yC3DdoNlfa-1pGMIAv0-ZPshOaNVDzA' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMDNiNjMwMDAtMmMwOS00OWVhLTlkYzItMjRhNWNhOTJmZWM3IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4MzM4MDIxIiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0OTExNzQyNywib3JnX2lkIjoib3JnX0NDdDQyRElkSWtyWDYyTXEzRjQxIiwicHJvZmlsZV9pZCI6InByb18wVnZVZ2YzbnRHN0Nwc3pSdktPWiIsInRlbmFudF9pZCI6InB1YmxpYyJ9.bhM7ccmFRjHKlWQ99diZBrI68k91UIAJjoZ3vh_8wMY' \
--data '{
    "organization_name": "Platform Org"
}'

Expected Response:

{
    "org_id": "org_f4sSAyBcjVzF2y0kNVBr",
    "org_name": "Platform Org",
    "org_type": "platform",
    "merchant_id": "merchant_1748946337",
    "merchant_account_type": "platform"
}

Create Merchant (Admin API):

Request:

curl --location 'http://localhost:8080/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_YchtwHauMbGFYcGKE6pSnwnTZq5xY8nH5rnhngBROK0W9beGOOUPfJ6gvHFETfnM' \
--data-raw '{
  "merchant_id": "merchant_1748954645",
  "locker_id": "m0010",
  "merchant_name": "Connected Merchant",
  "merchant_details": {
    "primary_contact_person": "John Test",
    "primary_email": "[email protected]",
    "primary_phone": "sunt laborum",
    "secondary_contact_person": "John Test2",
    "secondary_email": "[email protected]",
    "secondary_phone": "cillum do dolor id",
    "website": "https://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",
      "first_name":"john",
      "last_name":"Doe"
    }
  },
  "organization_id": "org_f4sSAyBcjVzF2y0kNVBr", 
  "return_url": "https://google.com/success",
  "webhook_details": {
    "webhook_version": "1.0.1",
    "webhook_username": "ekart_retail",
    "webhook_password": "password_ekart@123",
    "webhook_url":"https://webhook.site",
    "payment_created_enabled": true,
    "payment_succeeded_enabled": true,
    "payment_failed_enabled": true
  },
  "sub_merchants_enabled": false,
  "parent_merchant_id":"merchant_123",
  "metadata": {
    "city": "NY",
    "unit": "245"
  },
  "primary_business_details": [
    {
      "country": "US",
      "business": "default"
    }
  ],
  "merchant_account_type": "standard" 
}'

Expected Response:

{
    "merchant_id": "merchant_1748954658",
    "merchant_name": "Connected Merchant",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "ORSBBtzGCHe5xTQWyjU2VxEqEEC223hCzS5dOSHHUgOse74jmi8aDRqR6556hrxu",
    "redirect_to_merchant_with_http_post": false,
    "merchant_details": {
        "primary_contact_person": "John Test",
        "primary_phone": "sunt laborum",
        "primary_email": "[email protected]",
        "secondary_contact_person": "John Test2",
        "secondary_phone": "cillum do dolor id",
        "secondary_email": "[email protected]",
        "website": "https://www.example.com",
        "about_business": "Online Retail with a wide selection of organic products for North America",
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "john",
            "last_name": "Doe"
        }
    },
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true
    },
    "payout_routing_algorithm": null,
    "sub_merchants_enabled": false,
    "parent_merchant_id": null,
    "publishable_key": "pk_dev_1541e0af88014d4092be7e323bfc7b3a",
    "metadata": {
        "city": "NY",
        "unit": "245",
        "compatible_connector": null
    },
    "locker_id": "m0010",
    "primary_business_details": [
        {
            "country": "US",
            "business": "default"
        }
    ],
    "frm_routing_algorithm": null,
    "organization_id": "org_f4sSAyBcjVzF2y0kNVBr",
    "is_recon_enabled": false,
    "default_profile": "pro_wXPSR3hvAgWC9dx4B4QB",
    "recon_status": "not_requested",
    "pm_collect_link_config": null,
    "product_type": "orchestration",
    "merchant_account_type": "standard"
}

User Create Merchant API:

Request:

curl --location 'http://localhost:8080/user/create_merchant' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMDNiNjMwMDAtMmMwOS00OWVhLTlkYzItMjRhNWNhOTJmZWM3IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4OTQ2MzM3Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0OTExOTIzNSwib3JnX2lkIjoib3JnX2Y0c1NBeUJjalZ6RjJ5MGtOVkJyIiwicHJvZmlsZV9pZCI6InByb19QeEhmUzh1S2dYQWZOd2FkeFRudCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.TP03f06-NGhUjsfLTajO0TyK1OHLKE1Dq-DDQqyhRM0' \
--data '{
    "company_name": "Standard Merchant 2",
    "product_type": "orchestration",
    "merchant_account_type": "standard" 
}'

Expected Response:

{
    "merchant_id": "merchant_1748954749",
    "merchant_name": "Standard Merchant 2",
    "product_type": "orchestration",
    "merchant_account_type": "standard",
    "version": "v1"
}

Test Cases for Merchant Account Creation

OrganizationType::Standard

merchant_account_type in request Expected Behavior Outcome
None Treated as Standard Standard Merchant account is created
Standard Accepted Standard Merchant account is created
Connected Not allowed Rejected with 400 (must be Standard)

OrganizationType::Platform (Platform merchant already exists)

(Platform Merchant can only be created when creating a Platform Organization)

merchant_account_type in request allow_connected_merchants Expected Behavior Outcome
None any Defaults to Standard Standard merchant account is created
Standard any Accepted Standard merchant account is created
Connected true Accepted Connected merchant account is created
Connected false Not allowed Rejected with 400 (Connected not allowed)

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

@tsdk02 tsdk02 self-assigned this Jun 3, 2025
@tsdk02 tsdk02 requested a review from a team as a code owner June 3, 2025 12:49
@tsdk02 tsdk02 added the C-feature Category: Feature request or enhancement label Jun 3, 2025
@tsdk02 tsdk02 requested review from a team as code owners June 3, 2025 12:49
@semanticdiff-com
Copy link

semanticdiff-com bot commented Jun 3, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/common_enums/src/enums.rs  93% smaller
  crates/router/src/services/authentication.rs  29% smaller
  crates/router/src/core/admin.rs  16% smaller
  crates/openapi/src/openapi.rs  14% smaller
  crates/router/src/routes/app.rs  2% smaller
  api-reference/openapi_spec.json  0% smaller
  config/config.example.toml Unsupported file format
  config/deployments/integration_test.toml Unsupported file format
  config/deployments/production.toml Unsupported file format
  config/deployments/sandbox.toml Unsupported file format
  config/development.toml Unsupported file format
  config/docker_compose.toml Unsupported file format
  crates/api_models/src/admin.rs  0% smaller
  crates/api_models/src/user.rs  0% smaller
  crates/common_enums/src/enums/accounts.rs  0% smaller
  crates/router/src/configs/settings.rs  0% smaller
  crates/router/src/configs/validations.rs  0% smaller
  crates/router/src/types/domain/user.rs  0% smaller
  crates/router/src/utils/user.rs  0% smaller

@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Jun 3, 2025
hrithikesh026
hrithikesh026 previously approved these changes Jun 5, 2025
Copy link
Contributor

@hrithikesh026 hrithikesh026 left a comment

Choose a reason for hiding this comment

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

LGTM

#[router_derive::diesel_enum(storage_type = "text")]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum MerchantAccountRequestType {
Copy link
Contributor

Choose a reason for hiding this comment

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

seems an overkill to put this as common enums and deriving diesel stuff as this is specifically used for API request.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Expecting to use the same enum for the preferred merchant account creation as part of the platform organization settings - to be stored in the db, later.

@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jun 6, 2025
Merged via the queue into main with commit cb3aba8 Jun 6, 2025
15 of 20 checks passed
@Gnanasundari24 Gnanasundari24 deleted the onboarding-standard-merchants-platform-org branch June 6, 2025 20:02
pixincreate added a commit that referenced this pull request Jun 9, 2025
…nktransfer

* 'main' of github.com:juspay/hyperswitch: (211 commits)
  feat(tokenio): Add OpenBanking Redirection Flow (#8152)
  fix: Unified scarf setup (#8238)
  feat(health): Health check for Decision engine (#8243)
  chore: Update apple pay currency filter configs (