Skip to content

feat(subscriptions): Add client secret auth support in subscriptions APIs#9713

Merged
likhinbopanna merged 40 commits intomainfrom
subscriptions-client-auth
Oct 8, 2025
Merged

feat(subscriptions): Add client secret auth support in subscriptions APIs#9713
likhinbopanna merged 40 commits intomainfrom
subscriptions-client-auth

Conversation

@Sarthak1799
Copy link
Contributor

@Sarthak1799 Sarthak1799 commented Oct 7, 2025

Type of Change

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

Description

This pull request introduces several enhancements and refactors to the subscription API, focusing on improving authentication, response structure, and data handling. The main changes include adding payment and invoice details to subscription responses, updating authentication logic to support client secrets in queries, and refactoring handler methods for better error handling and extensibility.

Subscription Response Improvements

  • Added payment and invoice fields to the SubscriptionResponse struct to provide more detailed information about payments and invoices associated with a subscription.
  • Updated the PaymentResponseData struct to use a Secret<String> for the client_secret field, improving security and consistency.

Authentication and Query Handling

  • Introduced a new GetSubscriptionQuery struct to allow passing a client secret when fetching subscription details, and implemented ClientSecretFetch for relevant subscription request/query types. [1] [2]
  • Refactored authentication logic in subscription route handlers (get_subscription, get_subscription_plans, and confirm_subscription) to extract and validate client secrets from query payloads, improving security and flexibility. [1] [2] [3] [4]

Handler and Response Refactoring

  • Refactored the to_subscription_response method in SubscriptionWithHandler to accept optional payment and invoice parameters, and handle invoice conversion with error reporting for invalid currency values. [1] [2]
  • Updated core subscription logic to use the new response structure and refactored method signatures for consistency, including changes to how responses are generated and returned. [1] [2] [3] [4]

These changes collectively improve the robustness and extensibility of the subscription API, making it easier to integrate payment and invoice details while strengthening authentication mechanisms.

Additional Changes

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

Motivation and Context

How did you test it?

  1. Subscription create
curl --location 'http://localhost:8080/subscriptions/create' \
--header 'Content-Type: application/json' \
--header 'X-Profile-Id: pro_CohRshEanxkKSMHgyu6a' \
--header 'api-key: dev_tV0O30052zhBCqdrhGMfQxMN0DerXwnMkNHX6ndCbs0BovewetTaXznBQOCLGAi2' \
--data '{
    "customer_id": "cus_d64F9yomaDMqbTDlxw3g",
    "amount": 14100,
    "currency": "USD",
    "payment_details": {
        "authentication_type": "no_three_ds",
        "setup_future_usage": "off_session",
        "capture_method": "automatic",
        "return_url": "https://google.com"
    }
}'

Response -

{"id":"sub_8zxmAZAfS0eTL8zRJRk7","merchant_reference_id":null,"status":"created","plan_id":null,"profile_id":"pro_CohRshEanxkKSMHgyu6a","client_secret":"sub_8zxmAZAfS0eTL8zRJRk7_secret_IGg9yCNzrzoziV3odFLt","merchant_id":"merchant_1759849271","coupon_code":null,"customer_id":"cus_d64F9yomaDMqbTDlxw3g","payment":{"payment_id":"pay_pPn6Tz2m3WrOIzANMF2g","status":"requires_payment_method","amount":14100,"currency":"USD","connector":null,"payment_method_id":null,"payment_experience":null,"error_code":null,"error_message":null,"payment_method_type":null,"client_secret":"pay_pPn6Tz2m3WrOIzANMF2g_secret_Wxi6r52cBxz0ujhcWpAh"},"invoice":{"id":"invoice_nEqu7GMVqNMRzBorC9BS","subscription_id":"sub_8zxmAZAfS0eTL8zRJRk7","merchant_id":"merchant_1759849271","profile_id":"pro_CohRshEanxkKSMHgyu6a","merchant_connector_id":"mca_S0OzkqOOhMZs2jJQPSZo","payment_intent_id":"pay_pPn6Tz2m3WrOIzANMF2g","payment_method_id":null,"customer_id":"cus_d64F9yomaDMqbTDlxw3g","amount":14100,"currency":"USD","status":"invoice_created"}}
  1. Get plans
curl --location 'http://localhost:8080/subscriptions/plans?limit=2&offset=0&client_secret=sub_8zxmAZAfS0eTL8zRJRk7_secret_IGg9yCNzrzoziV3odFLt' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_febeb0fab3be43c79024efaf99764d63' \
--header 'X-Profile-Id: pro_CohRshEanxkKSMHgyu6a'

Response -

[{"plan_id":"cbdemo_enterprise-suite","name":"Enterprise Suite","description":"High-end customer support suite with enterprise-grade solutions.","price_id":[{"price_id":"cbdemo_enterprise-suite-monthly","plan_id":"cbdemo_enterprise-suite","amount":14100,"currency":"INR","interval":"Month","interval_count":1,"trial_period":null,"trial_period_unit":null},{"price_id":"cbdemo_enterprise-suite-annual","plan_id":"cbdemo_enterprise-suite","amount":169000,"currency":"INR","interval":"Year","interval_count":1,"trial_period":null,"trial_period_unit":null}]},{"plan_id":"cbdemo_business-suite","name":"Business Suite","description":"Advanced customer support plan with premium features.","price_id":[{"price_id":"cbdemo_business-suite-monthly","plan_id":"cbdemo_business-suite","amount":9600,"currency":"INR","interval":"Month","interval_count":1,"trial_period":null,"trial_period_unit":null},{"price_id":"cbdemo_business-suite-annual","plan_id":"cbdemo_business-suite","amount":115000,"currency":"INR","interval":"Year","interval_count":1,"trial_period":null,"trial_period_unit":null}]}]
  1. Confirm subscription -
curl --location 'http://localhost:8080/subscriptions/sub_8zxmAZAfS0eTL8zRJRk7/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-Profile-Id: pro_CohRshEanxkKSMHgyu6a' \
--header 'api-key: pk_dev_febeb0fab3be43c79024efaf99764d63' \
--data '{
    "item_price_id": "cbdemo_enterprise-suite-monthly",
    "description": "Hello this is description",
    "client_secret": "sub_8zxmAZAfS0eTL8zRJRk7_secret_IGg9yCNzrzoziV3odFLt",
    "shipping": {
        "address": {
            "state": "zsaasdas",
            "city": "Banglore",
            "country": "US",
            "line1": "sdsdfsdf",
            "line2": "hsgdbhd",
            "line3": "alsksoe",
            "zip": "571201",
            "first_name": "joseph",
            "last_name": "doe"
        },
        "phone": {
            "number": "123456789",
            "country_code": "+1"
        }
    },
    "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": "123456789",
            "country_code": "+1"
        }
    },
    "payment_details": {
        "payment_method": "card",
        "payment_method_type": "credit",
        "payment_method_data": {
            "card": {
                "card_number": "4111111111111111",
                "card_exp_month": "03",
                "card_exp_year": "2030",
                "card_holder_name": "CLBRW dffdg",
                "card_cvc": "737"
            }
        },
        "customer_acceptance": {
            "acceptance_type": "online",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "127.0.0.1",
                "user_agent": "amet irure esse"
            }
        }
    }
}'

Response -

{"id":"sub_8zxmAZAfS0eTL8zRJRk7","merchant_reference_id":null,"status":"active","plan_id":null,"price_id":null,"coupon":null,"profile_id":"pro_CohRshEanxkKSMHgyu6a","payment":{"payment_id":"pay_pPn6Tz2m3WrOIzANMF2g","status":"succeeded","amount":14100,"currency":"USD","connector":"stripe","payment_method_id":"pm_ZAtcND5u4SoRq6DnTQET","payment_experience":null,"error_code":null,"error_message":null,"payment_method_type":"credit","client_secret":"pay_pPn6Tz2m3WrOIzANMF2g_secret_Wxi6r52cBxz0ujhcWpAh"},"customer_id":"cus_d64F9yomaDMqbTDlxw3g","invoice":{"id":"invoice_nEqu7GMVqNMRzBorC9BS","subscription_id":"sub_8zxmAZAfS0eTL8zRJRk7","merchant_id":"merchant_1759849271","profile_id":"pro_CohRshEanxkKSMHgyu6a","merchant_connector_id":"mca_S0OzkqOOhMZs2jJQPSZo","payment_intent_id":"pay_pPn6Tz2m3WrOIzANMF2g","payment_method_id":"pm_ZAtcND5u4SoRq6DnTQET","customer_id":"cus_d64F9yomaDMqbTDlxw3g","amount":14100,"currency":"USD","status":"payment_pending"},"billing_processor_subscription_id":"sub_8zxmAZAfS0eTL8zRJRk7"}

invoice -
image

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

@Sarthak1799 Sarthak1799 self-assigned this Oct 7, 2025
@semanticdiff-com
Copy link

semanticdiff-com bot commented Oct 7, 2025

@hyperswitch-bot hyperswitch-bot bot added the M-database-changes Metadata: This PR involves database schema changes label Oct 7, 2025
@Sarthak1799 Sarthak1799 linked an issue Oct 7, 2025 that may be closed by this pull request
2 tasks
@@ -0,0 +1,2 @@
-- Your SQL goes here
ALTER TABLE invoice ADD COLUMN IF NOT EXISTS connector_invoice_id VARCHAR(255); No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ALTER TABLE invoice ADD COLUMN IF NOT EXISTS connector_invoice_id VARCHAR(255);
ALTER TABLE invoice ADD COLUMN IF NOT EXISTS connector_invoice_id VARCHAR(64);

@Sarthak1799 Sarthak1799 removed the request for review from a team October 8, 2025 09:41
jagan-jaya
jagan-jaya previously approved these changes Oct 8, 2025
}

#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct GetSubscriptionQuery {
Copy link
Member

Choose a reason for hiding this comment

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

Get-subscription shouldn't be a client call, basically if a merchant wants to update their state with a response of hyperswitch then they shouldn't depend on the client to send data, instead they should depend on server to server communication which is safer and scalable with features

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently it works with both S2S as well as client. Should we remove the client auth support of this? @jarnura

Copy link
Contributor Author

Choose a reason for hiding this comment

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

have removed client secret support

Copy link
Contributor

@apoorvdixit88 apoorvdixit88 left a comment

Choose a reason for hiding this comment

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

Looks fine for dashboard changes.

@likhinbopanna likhinbopanna added this pull request to the merge queue Oct 8, 2025
Merged via the queue into main with commit 01b4d6a Oct 8, 2025
26 of 29 checks passed
@likhinbopanna likhinbopanna deleted the subscriptions-client-auth branch October 8, 2025 15:44
aadityaguptaa pushed a commit that referenced this pull request Nov 10, 2025
…APIs (#9713)

Co-authored-by: Prajjwal kumar <write2prajjwal@gmail.com>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Prajjwal Kumar <prajjwal.kumar@juspay.in>
Co-authored-by: Jagan <jaganelavarasan@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

M-database-changes Metadata: This PR involves database schema changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add Client Auth for Subscriptions APIs

7 participants