Skip to content

Conversation

@su-shivanshmathur
Copy link
Contributor

@su-shivanshmathur su-shivanshmathur commented Jan 6, 2026

Type of Change

Adding a new API for getting Payment Method Id ( GlobalPaymentMethodId ) from the payment token provided to it

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

Description

There is no way of getting the Payment method ID for the given token for now, so adding an API for the usecase

Screenshot 2026-01-06 at 4 24 21 AM

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. Create a Payment Method Session

Request

curl --location 'http://localhost:8080/v2/payment-method-sessions' \
--header 'x-profile-id: pro_9K59ZyPdQhHp2fgnk9FW' \
--header 'Authorization: api-key=API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
    "customer_id": "12345_cus_019b5979a1387ed1b3b314cbb56a656d",
     "billing": {
        "address": {
            "first_name": "John",
            "last_name": "Dough"
        },
        "email": "[email protected]"
    }
}'

Response

{
    "id": "12345_pms_019b904d507e73708c9480d1a1e050a7",
    "customer_id": "12345_cus_019b5979a1387ed1b3b314cbb56a656d",
    "billing": {
        "address": {
            "city": null,
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": null,
            "state": null,
            "first_name": "John",
            "last_name": "Dough",
            "origin_zip": null
        },
        "phone": null,
        "email": "[email protected]"
    },
    "psp_tokenization": null,
    "network_tokenization": null,
    "tokenization_data": null,
    "expires_at": "2026-01-05T22:50:44.638Z",
    "client_secret": "cs_019b904d507f7481be1d6717714526e1",
    "return_url": null,
    "next_action": null,
    "authentication_details": null,
    "associated_payment_methods": null,
    "associated_token_id": null,
    "storage_type": null
}
  1. Confirm Payment method session

Request

curl --location 'http://localhost:8080/v2/payment-method-sessions/12345_pms_019b904d507e73708c9480d1a1e050a7/confirm' \
--header 'x-profile-id: pro_9K59ZyPdQhHp2fgnk9FW' \
--header 'Authorization: publishable-key=pk_dev_4fb8a872ef0c4a208d8aa4ae0c314f49,client-secret=cs_019b904d507f7481be1d6717714526e1' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "John Doe",
            "card_cvc": "100"
        }
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit"
}'

Response

{
    "id": "12345_pms_019b904d507e73708c9480d1a1e050a7",
    "customer_id": "12345_cus_019b5979a1387ed1b3b314cbb56a656d",
    "billing": {
        "address": {
            "city": null,
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": null,
            "state": null,
            "first_name": "John",
            "last_name": "Dough",
            "origin_zip": null
        },
        "phone": null,
        "email": "[email protected]"
    },
    "psp_tokenization": null,
    "network_tokenization": null,
    "tokenization_data": null,
    "expires_at": "2026-01-05T22:50:44.638Z",
    "client_secret": "CLIENT_SECRET_REDACTED",
    "return_url": null,
    "next_action": null,
    "authentication_details": null,
    "associated_payment_methods": [
        "token_OVci7wWJf28RjQPWaJD1"
    ],
    "associated_token_id": null,
    "storage_type": null
}
  1. Get API to get payment method ID from token
curl -v --location 'http://localhost:8080/v2/payment-methods/token/token_OVci7wWJf28RjQPWaJD1/details' \
--header 'x-profile-id: pro_9K59ZyPdQhHp2fgnk9FW' \
--header 'Authorization: api-key=API_KEY' \
--header 'Content-Type: application/json'
{"id":"12345_pm_019b8eef5f077163a9f5b3b0973c4301","payment_method_token":"token_OVci7wWJf28RjQPWaJD1"}

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

@su-shivanshmathur su-shivanshmathur requested review from a team as code owners January 6, 2026 06:49
@semanticdiff-com
Copy link

semanticdiff-com bot commented Jan 6, 2026

@su-shivanshmathur su-shivanshmathur self-assigned this Jan 6, 2026
@codecov
Copy link

codecov bot commented Jan 6, 2026

Codecov Report

❌ Patch coverage is 7.46269% with 62 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@4df0779). Learn more about missing BASE report.

Files with missing lines Patch % Lines
crates/router/src/routes/payment_methods.rs 0.00% 35 Missing ⚠️
crates/router/src/core/payment_methods.rs 0.00% 19 Missing ⚠️
crates/api_models/src/events/payment.rs 0.00% 7 Missing ⚠️
crates/router/src/routes/lock_utils.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10834   +/-   ##
=======================================
  Coverage        ?    6.33%           
=======================================
  Files           ?     1273           
  Lines           ?   322138           
  Branches        ?        0           
=======================================
  Hits            ?    20394           
  Misses          ?   301744           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Base automatically changed from chore/payment-token-v2-changes to main January 6, 2026 11:59
@su-shivanshmathur su-shivanshmathur requested a review from a team as a code owner January 6, 2026 11:59
@su-shivanshmathur su-shivanshmathur changed the title feat(payment_methods): payment method id retrival from payment token for V2 feat(payment_methods): payment method id retrieval from payment token for V2 Jan 6, 2026
maverox
maverox previously approved these changes Jan 6, 2026
},
))
}
Ok(_) => Err(errors::ApiErrorResponse::PaymentMethodNotFound.into()),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we send an error in case of other kinds of token data?

Copy link
Contributor

Choose a reason for hiding this comment

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

in case guest checkout flow,
currently we have permenant card, but it should temporary.
@su-shivanshmathur we need to verify on how we are insert this payment method token, when storage type is volatile

Comment on lines +1209 to +1235
pub async fn get_data_for_token(
&self,
state: &SessionState,
) -> CustomResult<PaymentTokenData, errors::ApiErrorResponse> {
let redis_conn = state
.store
.get_redis_conn()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get redis connection")?;

logger::debug!(
"Fetching payment method token data from redis for key: {}",
self.key_for_token
);

let pm_token_data = redis_conn
.get_and_deserialize_key::<PaymentTokenData>(
&self.key_for_token.as_str().into(),
"Token Data",
)
.await
.map_err(|e| error_stack::report!(storage_impl::StorageError::from(e)))
.to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
message: "Payment method token either expired or does not exist".to_string(),
})?;
Ok(pm_token_data)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you once check if retrieve_payment_token_data fn from crates/router/src/core/payment_methods/utils.rs can be reused here?

Copy link
Contributor

@Sarthak1799 Sarthak1799 Jan 7, 2026

Choose a reason for hiding this comment

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

Let's refactor later on to depricate this utils fn if not required. @su-shivanshmathur

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

Copy link
Contributor

Choose a reason for hiding this comment

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

can we create an issue for this?

Sarthak1799
Sarthak1799 previously approved these changes Jan 7, 2026
@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Jan 8, 2026
"Payment Methods"
],
"summary": "Payment Method - Get Payment Method Token Data",
"description": "Retrieve the Payment method id associated with a payment method.",
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
"description": "Retrieve the Payment method id associated with a payment method.",
"description": "Retrieve the Payment method id associated with a payment method token.",


/// The tokenization id associated with the payment method
#[schema(value_type = String, example = "token_CSum555d9YxDOpGwYq6q")]
pub token: String,
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
pub token: String,
pub payment_method_token: String,

also please modify the doc comment.
we have a different tokenization id in our service. this will create confusion

.route(web::get().to(payment_methods::network_token_status_check_api)),
)
.service(
web::resource("/details/{temporary_token}").route(
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
web::resource("/details/{temporary_token}").route(
web::resource("/token/{payment_method_token}/details").route(

Comment on lines +1209 to +1235
pub async fn get_data_for_token(
&self,
state: &SessionState,
) -> CustomResult<PaymentTokenData, errors::ApiErrorResponse> {
let redis_conn = state
.store
.get_redis_conn()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get redis connection")?;

logger::debug!(
"Fetching payment method token data from redis for key: {}",
self.key_for_token
);

let pm_token_data = redis_conn
.get_and_deserialize_key::<PaymentTokenData>(
&self.key_for_token.as_str().into(),
"Token Data",
)
.await
.map_err(|e| error_stack::report!(storage_impl::StorageError::from(e)))
.to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
message: "Payment method token either expired or does not exist".to_string(),
})?;
Ok(pm_token_data)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

can we create an issue for this?

let temporary_token = temporary_token.clone();
async move {
let platform: domain::Platform = auth.platform;
payment_methods_routes::payment_method_get_token(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
payment_methods_routes::payment_method_get_token(
payment_methods_routes::payment_method_get_token_details_core(

},
))
}
Ok(_) => Err(errors::ApiErrorResponse::PaymentMethodNotFound.into()),
Copy link
Contributor

Choose a reason for hiding this comment

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

in case guest checkout flow,
currently we have permenant card, but it should temporary.
@su-shivanshmathur we need to verify on how we are insert this payment method token, when storage type is volatile

@bernard-eugine bernard-eugine added this pull request to the merge queue Jan 8, 2026
Merged via the queue into main with commit f928daf Jan 8, 2026
27 of 29 checks passed
@bernard-eugine bernard-eugine deleted the feat/payment-method-id-by-payment-token branch January 8, 2026 10:39
siaass842 pushed a commit that referenced this pull request Jan 14, 2026
… for V2 (#10834)

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

Labels

M-api-contract-changes Metadata: This PR involves API contract changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants