hyperswitch icon indicating copy to clipboard operation
hyperswitch copied to clipboard

feat(authentication): enable platform merchant API Key authentication for org-level operations

Open tsdk02 opened this issue 6 months ago • 1 comments

Type of Change

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

Description

This PR enables authenticated access for platform merchants via their API key to perform the following operations:

Merchant Account Operations

  • Create standard merchant accounts within the platform org
  • List merchant accounts
  • Retrieve a specific merchant account
  • Update a merchant account

API Key Operations

  • Create an API key for a standard merchant
  • List API keys for a standard merchant
  • Retrieve an API Key
  • Update an API key
  • Revoke an API key

Organization Operations

  • Retrieve organization details
  • Update organization details

Analytics (Organization level)

  • Metrics
  • Filters

All of the above have strict org-matching checks to ensure platform merchants can only access resources within their organization.

Introduced and integrated new auth flows to enforce this behavior:

  • PlatformOrgAdminAuth – For org-scoped APIs (e.g., merchant list, org update)
  • PlatformOrgAdminAuthWithMerchantIdFromRoute – For APIs scoped by merchant path param
  • Enhanced JWTAuthOrganizationFromRoute – Validates org_id in token matches path param

Each of these flows:

  • Validates platform merchant identity and scope
  • Ensures cross-org access is prevented
  • Supports fallback to Admin API Key when is_admin_auth_allowed is set (and also fallback merchant API key, if configured)

MerchantAccountType:

  • Added MerchantAccountType field in MerchantAccountResponse

Additional Changes

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

Motivation and Context

Platform merchants are intended to manage and orchestrate multiple standard merchant accounts under a single organization. However, until now, they couldn't interact with many core APIs using their own API key — including merchant management, organization operations, API key handling, and analytics access.

How did you test it?

Merchant Account APIs

1. Create Merchant

Request:

curl --location 'http://localhost:8080/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_30M0S1Q1phnSUXWbRmvSScAdShlCwLrqDYby1jCuc2tHXsstIvPRo5qy7Q65RJJO' \
--data-raw '{
  "merchant_id": "merchant_1748354786",
  "locker_id": "m0010",
  "merchant_name": "Platform API 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_CfdN8ia42BzMUrjbYNiM",
  "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"
    }
  ]
}'

Expected Response:

{
    "merchant_id": "merchant_1748339362",
    "merchant_name": "Platform API Merchant",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "ha1Rq2nQSzcCnEy3FBLKtnwPg8yc9RjMmyZboGNSEKJwKMM81K8CYXqJNWJKrp5E",
    "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_d8aba9f251c44ba8bda28d7b48103125",
    "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_CfdN8ia42BzMUrjbYNiM",
    "is_recon_enabled": false,
    "default_profile": "pro_iM8KYK4hLNSanTF8CFPR",
    "recon_status": "not_requested",
    "pm_collect_link_config": null,
    "product_type": "orchestration",
    "merchant_account_type": "connected"
}
Scenario Auth Type Expected Behavior
1.1 Platform API Key (same org) Merchant created
1.2 Platform API Key (different org) Unauthorized
1.3 Admin API Key Merchant created
1.4 Fallback API Key (config) Merchant created
1.5 Any other case Unauthorized

2. List Merchants

Request:

curl --location 'http://localhost:8080/accounts/list?organization_id=org_CfdN8ia42BzMUrjbYNiM' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-Merchant-Id: merchant_1748247188' \
--header 'api-key: test_admin' \
--data ''

Expected Response:

[
    {
        "merchant_id": "merchant_1748339023",
        "merchant_name": "Hyperswitch",
        "return_url": null,
        "enable_payment_response_hash": true,
        "payment_response_hash_key": "Y6pZAHKZCteIlcLlvPVKpj4auwVMOUyp4Gl5P3HSMCsE0W71XsqZNgjlfHInswrN",
        "redirect_to_merchant_with_http_post": false,
        "merchant_details": null,
        "webhook_details": null,
        "payout_routing_algorithm": null,
        "sub_merchants_enabled": false,
        "parent_merchant_id": null,
        "publishable_key": "pk_dev_9a085084db3943589d04e596c790e2a2",
        "metadata": null,
        "locker_id": null,
        "primary_business_details": [],
        "frm_routing_algorithm": null,
        "organization_id": "org_CfdN8ia42BzMUrjbYNiM",
        "is_recon_enabled": false,
        "default_profile": "pro_mky2SQ3h1hmmUDkVxlVU",
        "recon_status": "not_requested",
        "pm_collect_link_config": null,
        "product_type": "orchestration",
        "merchant_account_type": "platform"
    },
    {
        "merchant_id": "merchant_1748339074",
        "merchant_name": "Admin Merchant",
        "return_url": "https://google.com/success",
        "enable_payment_response_hash": true,
        "payment_response_hash_key": "3LoplBmFLLUIysEIr8o4FRQF2lT2bfBpsmtNZNCat7A9SV8gEUGDTV2dznCrXNqJ",
        "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_844d5c1dbe96424784c30ef393e76619",
        "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_CfdN8ia42BzMUrjbYNiM",
        "is_recon_enabled": false,
        "default_profile": "pro_mwDaCNBw8LirhyMZGf1B",
        "recon_status": "not_requested",
        "pm_collect_link_config": null,
        "product_type": "orchestration",
        "merchant_account_type": "connected"
    }
]
Scenario Auth Type Expected Behavior
2.1 Platform API Key + matching org_id in query Merchant list returned
2.2 Platform API Key + mismatched org_id Unauthorized
2.3 Admin API Key + any org_id Merchant list returned
2.4 Fallback API Key (config) Merchant list returned
2.5 JWT + matching org_id in query Merchant list returned
2.6 JWT + mismatched org_id InvalidJwtToken
2.7 Any other case Unauthorized

3. Retrieve Merchant

Request:

curl --location 'http://localhost:8080/accounts/merchant_1748247055' \
--header 'Accept: application/json' \
--header 'api-key: test_admin'

Expected Response:

{
    "merchant_id": "merchant_1748247055",
    "merchant_name": "Connected JWT",
    "return_url": null,
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "R214M17EUqiZyDbkP3Slv5sB8WVLUHONaYm3Ly6YOfPPYzdiqgvCi6LOMVzNmi6p",
    "redirect_to_merchant_with_http_post": false,
    "merchant_details": null,
    "webhook_details": null,
    "payout_routing_algorithm": null,
    "sub_merchants_enabled": false,
    "parent_merchant_id": null,
    "publishable_key": "pk_dev_7c64347723494ab1ad56df8180385bdd",
    "metadata": null,
    "locker_id": null,
    "primary_business_details": [],
    "frm_routing_algorithm": null,
    "organization_id": "org_l8ol6KqrQ5eaHBPwZ2V3",
    "is_recon_enabled": false,
    "default_profile": "pro_rOryKpNr5QUEynTrT0TD",
    "recon_status": "not_requested",
    "pm_collect_link_config": null,
    "product_type": "orchestration",
    "merchant_account_type": "connected"
}
Scenario Auth Type Expected Behavior
3.1 Platform API Key + merchant from same org Merchant retrieved
3.2 Platform API Key + merchant from different org Unauthorized
3.3 Admin API Key Merchant retrieved
3.4 Fallback API Key (config) Merchant retrieved
3.5 JWT + merchant_id in org Merchant retrieved
3.6 JWT + mismatched merchant_id or org InvalidJwtToken
3.7 Any other case Unauthorized

4. Update Merchant

Request:

curl --location 'http://localhost:8080/accounts/merchant_1748244954' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--data-raw '{
  "merchant_id": "merchant_1744225676",
  "locker_id": "m0010",
  "merchant_name": "Platform 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"
    }
  },
  "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"
    }
  ]
}'

Expected Response:

{
    "merchant_id": "merchant_1748244954",
    "merchant_name": "Platform Merchant",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "1zbZFZFo6yrsd44wwMjzaFC3GlLCxAPWhPYlGcWu7GSzDblhl4g8tRl2EdDTRpke",
    "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_9a9589f79f664920bb63c5ca1a5448cd",
    "metadata": {
        "city": "NY",
        "unit": "245"
    },
    "locker_id": "m0010",
    "primary_business_details": [
        {
            "country": "US",
            "business": "default"
        }
    ],
    "frm_routing_algorithm": null,
    "organization_id": "org_l8ol6KqrQ5eaHBPwZ2V3",
    "is_recon_enabled": false,
    "default_profile": null,
    "recon_status": "not_requested",
    "pm_collect_link_config": null,
    "product_type": "orchestration"
}
Scenario Auth Type Expected Behavior
4.1 Platform API Key + merchant from same org Merchant updated
4.2 Platform API Key + merchant from different org Unauthorized
4.3 Admin API Key Merchant updated
4.4 Fallback API Key (config) Merchant updated
4.5 JWT + merchant_id in org Merchant updated
4.6 JWT + mismatched merchant_id or org InvalidJwtToken
4.7 Any other case Unauthorized

API Key APIs

5. Create API Key

Request:

curl --location 'http://localhost:8080/api_keys/merchant_1748339362' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_30M0S1Q1phnSUXWbRmvSScAdShlCwLrqDYby1jCuc2tHXsstIvPRo5qy7Q65RJJO' \
--data '{
  "name": "Nike API Key 2",
  "description": null,
  "expiration": "2038-01-19T03:14:08.000Z"
}'

Expected Response:

{
    "key_id": "dev_nNAgIKTXitQ6BcLVZae5",
    "merchant_id": "merchant_1748339362",
    "name": "Nike API Key 2",
    "description": null,
    "api_key": "dev_3CaIJZiLTY7lVafRs9atnxAPrHREm4yauTrvhQD8Y44KwwXCbu25fIm64QEGbCz2",
    "created": "2025-05-27T09:49:50.936Z",
    "expiration": "2038-01-19T03:14:08.000Z"
}
Scenario Auth Type Expected Behavior
5.1 Platform API Key + merchant from same org API Key created
5.2 Platform API Key + merchant from different org Unauthorized
5.3 Admin API Key API Key created
5.4 Fallback API Key (config) API Key created
5.5 JWT + merchant_id in org API Key created
5.6 JWT + merchant in different org Forbidden / InvalidJwtToken
5.7 Any other case Unauthorized

6. List API Keys

Request:

curl --location 'http://localhost:8080/api_keys/merchant_1748252478/list' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_1jmsnLQvYEan1qFCxMxNhMbT8xre9LvGJbiRzS90ZyBHO3d9smCbdNg0MjBWMroP'

Expected Response:

[
    {
        "key_id": "dev_Upyxxd2nyxZ6ptIe70zE",
        "merchant_id": "merchant_1748252478",
        "name": "Nike API Key 2",
        "description": null,
        "prefix": "dev_nRxdo8Wu",
        "created": "2025-05-26T10:58:25.475Z",
        "expiration": "2038-01-19T03:14:08.000Z"
    },
    {
        "key_id": "dev_PxEjbjfyf1qykaMd7s7l",
        "merchant_id": "merchant_1748252478",
        "name": "Nike API Key 2",
        "description": null,
        "prefix": "dev_f9MG2CJf",
        "created": "2025-05-26T10:58:30.545Z",
        "expiration": "2038-01-19T03:14:08.000Z"
    }
]
Scenario Auth Type Expected Behavior
6.1 Platform API Key + merchant from same org API Keys listed
6.2 Platform API Key + merchant from different org Unauthorized
6.3 Admin API Key API Keys listed
5.4 Fallback API Key (config) API Keys listed
6.5 JWT + matching merchant & permission API Keys listed
6.6 JWT + merchant in different org InvalidJwtToken or Forbidden
6.7 Any other case Unauthorized

7. Retrieve API Key

Request:

curl --location 'http://localhost:8080/api_keys/merchant_1748339362/dev_uHMMaVMYseYOLfhZrNEL' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin'

Expected Response:

{
    "key_id": "dev_uHMMaVMYseYOLfhZrNEL",
    "merchant_id": "merchant_1748339362",
    "name": "Nike API Key 2",
    "description": null,
    "prefix": "dev_wKJ5D5LU",
    "created": "2025-05-27T14:15:16.455Z",
    "expiration": "2038-01-19T03:14:08.000Z"
}
Scenario Auth Type Expected Behavior
7.1 Platform API Key + merchant from same org API Key retrieved
7.2 Platform API Key + merchant from different org Unauthorized
7.3 Admin API Key API Key retrieved
7.4 Fallback API Key (config) API Key retrieved
7.5 JWT + matching merchant & permission API Key retrieved
7.6 JWT + merchant in different org InvalidJwtToken or Forbidden
7.7 Any other case Unauthorized

8. Update API Key

Request:

curl --location 'http://localhost:8080/api_keys/merchant_1748252478/dev_b7kajJZbITKra0FdwDne' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY2Y1ZTMwYjMtOTZkMi00YWJkLWJlMzMtYjhmOGFlOWRiMmZkIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4MjUyNDc4Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0ODQyOTg2NSwib3JnX2lkIjoib3JnX2w4b2w2S3FyUTVlYUhCUHdaMlYzIiwicHJvZmlsZV9pZCI6InByb19yM0R3VlVHUnZaVExZWEx5eHZkZSIsInRlbmFudF9pZCI6InB1YmxpYyJ9.ElVIJMr7-FPkW3N3h_cVyrOxEh4q1_u94KHVdVnJQ9g' \
--data '{
  "name": "Test API Key 3",
  "description": "My very awesome API key",
  "expiration": null
}'

Expected Response:

{
    "key_id": "dev_b7kajJZbITKra0FdwDne",
    "merchant_id": "merchant_1748252478",
    "name": "Test API Key 3",
    "description": "My very awesome API key",
    "prefix": "dev_5m97MTk0",
    "created": "2025-05-26T10:59:56.935Z",
    "expiration": "2038-01-19T03:14:08.000Z"
}
Scenario Auth Type Expected Behavior
8.1 Platform API Key + merchant from same org API Key updated
8.2 Platform API Key + merchant from different org Unauthorized
8.3 Admin API Key API Key updated
8.4 Fallback API Key (config) API Key updated
8.5 JWT + matching merchant & permission API Key updated
8.6 JWT + merchant in different org InvalidJwtToken or Forbidden
8.7 Any other case Unauthorized

9. Revoke API Key

Request:

curl --location --request DELETE 'http://localhost:8080/api_keys/merchant_1748252478/dev_b7kajJZbITKra0FdwDne' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY2Y1ZTMwYjMtOTZkMi00YWJkLWJlMzMtYjhmOGFlOWRiMmZkIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4MjUyNDc4Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0ODQyOTg2NSwib3JnX2lkIjoib3JnX2w4b2w2S3FyUTVlYUhCUHdaMlYzIiwicHJvZmlsZV9pZCI6InByb19yM0R3VlVHUnZaVExZWEx5eHZkZSIsInRlbmFudF9pZCI6InB1YmxpYyJ9.ElVIJMr7-FPkW3N3h_cVyrOxEh4q1_u94KHVdVnJQ9g'

Expected Response:

{
    "merchant_id": "merchant_1748339362",
    "key_id": "dev_uHMMaVMYseYOLfhZrNEL",
    "revoked": true
}
Scenario Auth Type Expected Behavior
9.1 Platform API Key + merchant from same org API Key revoked
9.2 Platform API Key + merchant from different org Unauthorized
9.3 Admin API Key API Key revoked
9.4 Fallback API Key (config) API Key revoked
9.5 JWT + matching merchant & permission API Key revoked
9.6 JWT + merchant in different org InvalidJwtToken or Forbidden
9.7 Any other case Unauthorized

Organization APIs

10. Retrieve Org

Request:

curl --location 'http://localhost:8080/organization/org_l8ol6KqrQ5eaHBPwZ2V3' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY2Y1ZTMwYjMtOTZkMi00YWJkLWJlMzMtYjhmOGFlOWRiMmZkIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4MjUyNDI5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0ODQyOTI2MCwib3JnX2lkIjoib3JnX2w4b2w2S3FyUTVlYUhCUHdaMlYzIiwicHJvZmlsZV9pZCI6InByb19GemFxMVVIdDh5RG5ZUVBOVzlhRSIsInRlbmFudF9pZCI6InB1YmxpYyJ9.TKS85mCJxR0jqMNsYZ7YL4FrwH8K2OOTPp6O_SHdq8w'

Expected Response:

{
    "organization_id": "org_l8ol6KqrQ5eaHBPwZ2V3",
    "organization_name": "Platform Organization 3",
    "organization_details": null,
    "metadata": null,
    "modified_at": "2025-05-26 10:48:43.380292",
    "created_at": "2025-05-26 07:35:54.645102"
}
Scenario Auth Type Expected Behavior
10.1 Platform API Key Organization retrieved
10.2 Platform API Key + different org Unauthorized
10.3 Admin API Key Organization retrieved
10.4 Fallback API Key (config) Organization retrieved
10.5 JWT + matching organization Organization retrieved
10.6 JWT + different org InvalidJwtToken or Forbidden
10.7 Any other case Unauthorized

11. Update Org

Request:

curl --location --request PUT 'http://localhost:8080/organization/org_l8ol6KqrQ5eaHBPwZ2V3' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY2Y1ZTMwYjMtOTZkMi00YWJkLWJlMzMtYjhmOGFlOWRiMmZkIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQ4MjUyNDI5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0ODQyOTI2MCwib3JnX2lkIjoib3JnX2w4b2w2S3FyUTVlYUhCUHdaMlYzIiwicHJvZmlsZV9pZCI6InByb19GemFxMVVIdDh5RG5ZUVBOVzlhRSIsInRlbmFudF9pZCI6InB1YmxpYyJ9.TKS85mCJxR0jqMNsYZ7YL4FrwH8K2OOTPp6O_SHdq8w' \
--data '{
    "organization_name": "Platform Organization 3"
}'

Expected Response:

{
    "organization_id": "org_l8ol6KqrQ5eaHBPwZ2V3",
    "organization_name": "Platform Organization 3",
    "organization_details": null,
    "metadata": null,
    "modified_at": "2025-05-26 10:48:43.380292",
    "created_at": "2025-05-26 07:35:54.645102"
}
Scenario Auth Type Expected Behavior
11.1 Platform API Key Organization updated
11.2 Platform API Key + different org Unauthorized
11.3 Admin API Key Organization updated
11.4 Fallback API Key (config) Organization updated
11.5 JWT + matching organization Organization updated
11.6 JWT + different org InvalidJwtToken or Forbidden
11.7 Any other case Unauthorized

Analytics APIs

12. Payments Metrics

Request:

curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-03-01T18:30:00Z",
            "endTime": "2025-05-31T09:22:00Z"
        },
        "filters": {
            "currency": [
                "USD"
            ]
        },
        "source": "BATCH",
        "metrics": [
            "payment_success_rate"
        ],
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "delta": true
    }
]'

Expected Response:

{
    "queryData": [
        {
            "payment_success_rate": 100.0,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "currency": null,
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": null,
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "time_range": {
                "start_time": "2025-05-26T00:00:00.000Z",
                "end_time": "2025-05-26T23:00:00.000Z"
            },
            "time_bucket": "2025-05-26 00:00:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 0,
            "total_payment_processed_amount_in_usd": null,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": null,
            "total_payment_processed_count": 0,
            "total_payment_processed_count_without_smart_retries": 0,
            "total_failure_reasons_count": 0,
            "total_failure_reasons_count_without_smart_retries": 0
        }
    ]
}
Scenario Auth Type Expected Behavior
12.1 Platform API Key Access to analytics
12.3 Admin API Key Unauthorized
12.4 Fallback API Key (config) Unauthorized
12.5 JWT Access to analytics
12.7 Any other case Unauthorized

Checklist

  • [x] I formatted the code cargo +nightly fmt --all
  • [x] I addressed lints thrown by cargo clippy
  • [x] I reviewed the submitted code
  • [ ] I added unit tests for my changes where possible

tsdk02 avatar May 27 '25 13:05 tsdk02