Skip to content

Conversation

kashif-m
Copy link
Contributor

@kashif-m kashif-m commented Jun 20, 2025

feat(payouts): allow payout_id to be configurable in API request
feat(payouts): add merchant_order_reference_id for referencing payouts

Type of Change

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

Description

This pull request introduces two main features for payouts:

  1. Configurable payout_id in API Requests:

    • The payout_id field in payout creation API requests can now be optionally provided by the merchant. If provided, this ID will be used for the payout. If not provided, the system will generate one.
    • Internally, the usage of payout_id has been standardized to use the strongly-typed common_utils::id_type::PayoutId instead of String. This change has been propagated throughout relevant structs and functionalities like PayoutsData, data handling logic in crates/router/src/core/utils.rs, test utilities and DB queries.
  2. merchant_order_reference_id for Payout Referencing:

    • The merchant_order_reference_id field has been added/updated in payout API models (e.g., PayoutListFilterConstraints in crates/api_models/src/payouts.rs). This allows merchants to use their own unique identifier to reference payouts.

Refactoring and Connector Updates:

  • To support the id_type::PayoutId change and ensure correct data flow, connector integrations (Adyen, Adyenplatform, Cybersource, Nomupay) have been refactored.
  • Connectors now consistently use RouterData.connector_request_reference_id (which typically holds the payout_attempt_id as a String) when a string-based reference is required by the external service, rather than converting the internal PayoutsData.payout_id. This ensures that connectors receive the appropriate string identifier (e.g., payout_attempt_id) they expect.

Additional Changes

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

Motivation and Context

These changes address the need for greater flexibility and type safety in payout processing, as outlined in GitHub issues #8392 and #1321.

  • Configurable payout_id: Allows merchants more control over their payout identifiers within the Hyperswitch.
  • merchant_order_reference_id: Provides a dedicated field for merchants to use their internal order or reference IDs.
  • PayoutId Type Standardization: Using common_utils::id_type::PayoutId enhances code robustness and maintainability by leveraging Rust's type system to prevent errors related to ID handling.
  • Connector Refactoring: Ensures that connectors use the correct string-based identifiers (like payout_attempt_id via connector_request_reference_id) required by external payout processors, maintaining correctness of integrations.

Links to issues:

How did you test it?

1. Card payouts via API

cURL

curl --location --request POST 'http://localhost:8080/payouts/create' \
    --header 'Content-Type: application/json' \
    --header 'api-key: dev_lAISInmiO4UNrMmvkJogzRVKEGKlBKQbRCBFOkLJTXmq6nsD5G1H65BjOd4H72H8' \
    --data '{"amount":100,"currency":"EUR","profile_id":"pro_vVSlzCG7M1GSX9SyssY8","customer_id":"cus_WULwykbL8laUbxDUeGEB","connector":["adyenplatform"],"description":"Its my first payout request","payout_type":"card","payout_method_data":{"card":{"card_number":"4111111111111111","expiry_month":"03","expiry_year":"2030"}},"billing":{"address":{"line1":"1467","line2":"Harrison Street","line3":"Harrison Street","city":"San Fransico","state":"CA","zip":"94122","country":"FR","first_name":"John","last_name":"Doe"}},"entity_type":"Individual","recurring":true,"metadata":{"ref":"123"},"confirm":true,"auto_fulfill":true}'

Response

{"payout_id":"ff21b89d-3cfd-4f0f-b3ff-c468d90d7074","merchant_id":"merchant_1751292662","amount":100,"currency":"EUR","connector":"adyenplatform","payout_type":"card","payout_method_data":{"card":{"card_issuer":null,"card_network":null,"card_type":null,"card_issuing_country":null,"bank_code":null,"last4":"1111","card_isin":"411111","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"2030","card_holder_name":null}},"billing":{"address":{"city":"San Fransico","country":"FR","line1":"1467","line2":"Harrison Street","line3":"Harrison Street","zip":"94122","state":"CA","first_name":"John","last_name":"Doe"},"phone":null,"email":null},"auto_fulfill":true,"customer_id":"cus_WULwykbL8laUbxDUeGEB","customer":{"id":"cus_WULwykbL8laUbxDUeGEB","name":"John Nether","email":null,"phone":"6168205362","phone_country_code":"+1"},"client_secret":"payout_ff21b89d-3cfd-4f0f-b3ff-c468d90d7074_secret_qzFALtOg6ZhYAOAUr2qY","return_url":null,"business_country":null,"business_label":null,"description":"Its my first payout request","entity_type":"Individual","recurring":true,"metadata":{"ref":"123"},"merchant_connector_id":"mca_SfssFvg5RBT2k7iKRRsS","status":"initiated","error_message":null,"error_code":null,"profile_id":"pro_vVSlzCG7M1GSX9SyssY8","created":"2025-06-30T14:12:47.886Z","connector_transaction_id":"38EBIX67HBSYZ30V","priority":null,"payout_link":null,"email":null,"name":"John Nether","phone":"6168205362","phone_country_code":"+1","unified_code":null,"unified_message":null,"payout_method_id":"pm_wScFhCfxELZ7gN13Nbxz"}
2. Card payouts via Payout Links

cURL

curl --location --request POST 'http://localhost:8080/payouts/create' \
    --header 'Content-Type: application/json' \
    --header 'api-key: dev_lAISInmiO4UNrMmvkJogzRVKEGKlBKQbRCBFOkLJTXmq6nsD5G1H65BjOd4H72H8' \
    --data '{"amount":1,"currency":"EUR","customer_id":"cus_WULwykbL8laUbxDUeGEB","description":"Its my first payout request","entity_type":"Individual","confirm":false,"auto_fulfill":true,"session_expiry":1000000,"profile_id":"pro_vVSlzCG7M1GSX9SyssY8","payout_link":true,"return_url":"https://www.google.com","payout_link_config":{"form_layout":"journey","theme":"#0066ff","logo":"https://hyperswitch.io/favicon.ico","merchant_name":"HyperSwitch Inc.","test_mode":true}}'

Response

{"payout_id":"2371746b-df3d-41da-8fa2-455faf921ea9","merchant_id":"merchant_1751292662","amount":1,"currency":"EUR","connector":null,"payout_type":null,"payout_method_data":null,"billing":null,"auto_fulfill":true,"customer_id":"cus_WULwykbL8laUbxDUeGEB","customer":{"id":"cus_WULwykbL8laUbxDUeGEB","name":"John Nether","email":null,"phone":"6168205362","phone_country_code":"+1"},"client_secret":"payout_2371746b-df3d-41da-8fa2-455faf921ea9_secret_VwDeIScMTLFzG7Iz1DZU","return_url":"https://www.google.com","business_country":null,"business_label":null,"description":"Its my first payout request","entity_type":"Individual","recurring":false,"metadata":{},"merchant_connector_id":null,"status":"requires_payout_method_data","error_message":null,"error_code":null,"profile_id":"pro_vVSlzCG7M1GSX9SyssY8","created":"2025-06-30T14:14:48.897Z","connector_transaction_id":null,"priority":null,"payout_link":{"payout_link_id":"payout_link_vITmtOWGkaUfeXopruRs","link":"http://localhost:8080/payout_link/merchant_1751292662/2371746b-df3d-41da-8fa2-455faf921ea9?locale=en"},"email":null,"name":"John Nether","phone":"6168205362","phone_country_code":"+1","unified_code":null,"unified_message":null,"payout_method_id":null}
Screenshot 2025-06-30 at 7 45 32 PM Screenshot 2025-06-30 at 7 45 48 PM Screenshot 2025-06-30 at 7 45 54 PM

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

feat(payouts): allow payout_id to be configurable in API request
feat(payouts): add merchant_order_reference_id for referencing payouts
@kashif-m kashif-m self-assigned this Jun 20, 2025
@kashif-m kashif-m requested review from a team as code owners June 20, 2025 04:35
Copy link

semanticdiff-com bot commented Jun 20, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/payouts/helpers.rs  92% smaller
  crates/router/src/workflows/outgoing_webhook_retry.rs  90% smaller
  crates/hyperswitch_domain_models/src/errors/api_error_response.rs  87% smaller
  crates/router/src/compatibility/stripe/errors.rs  80% smaller
  crates/router/src/routes/payout_link.rs  79% smaller
  crates/router/src/core/webhooks/incoming.rs  73% smaller
  crates/router/src/core/payments/routing.rs  69% smaller
  crates/storage_impl/src/redis/kv_store.rs  67% smaller
  crates/router/src/core/payouts.rs  66% smaller
  crates/router/src/core/payouts/validator.rs  58% smaller
  crates/router/src/core/payouts/retry.rs  55% smaller
  crates/router/src/core/payout_link.rs  50% smaller
  crates/diesel_models/src/query/generic_link.rs  41% smaller
  crates/router/src/routes/payouts.rs  41% smaller
  crates/router/src/compatibility/stripe/webhooks.rs  38% smaller
  crates/api_models/src/payouts.rs  32% smaller
  crates/storage_impl/src/payouts/payouts.rs  31% smaller
  crates/router/tests/connectors/utils.rs  30% smaller
  crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs  15% smaller
  api-reference/v2/openapi_spec_v2.json  6% smaller
  crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs  4% smaller
  crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs  4% smaller
  crates/storage_impl/src/payouts/payout_attempt.rs  3% smaller
  crates/diesel_models/src/schema.rs  2% smaller
  crates/diesel_models/src/schema_v2.rs  2% smaller
  crates/router/src/core/utils.rs  1% smaller
  crates/api_models/src/events/payouts.rs  1% smaller
  crates/router/src/utils.rs  1% smaller
  api-reference/v1/openapi_spec_v1.json  0% smaller
  crates/api_models/src/webhooks.rs  0% smaller
  crates/common_utils/src/events.rs  0% smaller
  crates/common_utils/src/id_type.rs  0% smaller
  crates/common_utils/src/id_type/payout.rs  0% smaller
  crates/common_utils/src/link_utils.rs  0% smaller
  crates/diesel_models/src/events.rs  0% smaller
  crates/diesel_models/src/generic_link.rs  0% smaller
  crates/diesel_models/src/payout_attempt.rs  0% smaller
  crates/diesel_models/src/payouts.rs  0% smaller
  crates/diesel_models/src/query/payout_attempt.rs  0% smaller
  crates/diesel_models/src/query/payouts.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/stripe/transformers/connect.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/wise/transformers.rs  0% smaller
  crates/hyperswitch_domain_models/src/payouts.rs  0% smaller
  crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs  0% smaller
  crates/hyperswitch_domain_models/src/payouts/payouts.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types.rs  0% smaller
  crates/router/src/core/payouts/transformers.rs  0% smaller
  crates/router/src/db/kafka_store.rs  0% smaller
  crates/router/src/events/outgoing_webhook_logs.rs  0% smaller
  crates/router/src/services/kafka/payout.rs  0% smaller
  crates/storage_impl/src/lib.rs  0% smaller
  crates/storage_impl/src/mock_db/payout_attempt.rs  0% smaller
  crates/storage_impl/src/mock_db/payouts.rs  0% smaller
  flake.nix Unsupported file format
  migrations/2025-06-19-170656_alter_payout_primary_key/down.sql Unsupported file format
  migrations/2025-06-19-170656_alter_payout_primary_key/up.sql Unsupported file format

@hyperswitch-bot hyperswitch-bot bot added M-database-changes Metadata: This PR involves database schema changes M-api-contract-changes Metadata: This PR involves API contract changes labels Jun 20, 2025
@kashif-m kashif-m linked an issue Jun 23, 2025 that may be closed by this pull request
2 tasks
Sarthak1799
Sarthak1799 previously approved these changes Jun 30, 2025
Copy link
Contributor

@Sarthak1799 Sarthak1799 left a comment

Choose a reason for hiding this comment

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

Routing file changes looks okay

@kashif-m
Copy link
Contributor Author

#8395 (comment)

Not possible currently @jarnura

Adding an issue for this - #8505

@kashif-m kashif-m dismissed stale reviews from Sarthak1799 and su-shivanshmathur via 1a2a3f2 July 1, 2025 07:58
jarnura
jarnura previously approved these changes Jul 1, 2025
jarnura
jarnura previously approved these changes Jul 1, 2025
@kashif-m kashif-m dismissed stale reviews from su-shivanshmathur and jarnura via f46c39a July 1, 2025 11:55
@Gnanasundari24 Gnanasundari24 enabled auto-merge July 1, 2025 13:19
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jul 1, 2025
Merged via the queue into main with commit a6e3d2c Jul 1, 2025
21 of 24 checks passed
@Gnanasundari24 Gnanasundari24 deleted the 8392-allow-payout_id_to-be-configurable branch July 1, 2025 14:45
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 M-database-changes Metadata: This PR involves database schema changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE] allow payout_id to be configurable
6 participants