Skip to content

feat(connector): add Ilixium routing via unified connector service - #13708

Open
shuklatushar226 wants to merge 3 commits into
mainfrom
feat/grace-ilixium
Open

feat(connector): add Ilixium routing via unified connector service#13708
shuklatushar226 wants to merge 3 commits into
mainfrom
feat/grace-ilixium

Conversation

@shuklatushar226

@shuklatushar226 shuklatushar226 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • New feature

Description

Registers Ilixium as a Hyperswitch connector so that card payments can be routed to the Unified Connector Service (UCS), where the actual Ilixium Direct API integration lives. There is no in-repo Ilixium HTTP integration — Ilixium is added to ucs_only_connectors, so every attempt takes the UCS gateway path.

Linked UCS PR: juspay/hyperswitch-prism#2125

What this does

  • Adds Ilixium to common_enums::Connector, euclid::enums::{Connector, RoutableConnectors} and the Connector -> RoutableConnectors mappings, so Connector::from_str("ilixium") (used by should_call_unified_connector_service) resolves and the connector is routable.

  • Adds a UCS-only connector stub at crates/hyperswitch_connectors/src/connectors/ilixium.rs (connector-template shape). It exists only so ConnectorData::get_connector_by_name / feature-matrix resolution succeed before the UCS/Direct decision is made; its only meaningful logic is validating the SignatureKey auth shape.

  • Adds ConnectorSpecificConfig::Ilixium in crates/router/src/core/unified_connector_service/connector_config.rs. Without this, build_connector_config_header returns an error and the UCS call fails. The x-connector-config header now carries:

    MCA field Ilixium meaning Where UCS uses it
    api_key Digest Calculation Password input to x-merchant-digest (never transmitted)
    key1 MerchantId request body merchant.merchantId
    api_secret AccountId request body merchant.accountId
  • Adds ilixium to ucs_only_connectors in config/development.toml, config/config.example.toml, config/deployments/env_specific.toml and config/deployments/integration_test.toml (deliberately not sandbox/production — no credentials yet).

  • Adds ilixium.base_url = "https://prprocessing.ilixium.com/platform/ili" to the config files, control-center connector config entries (SignatureKey, credit/debit card networks) and a cards required-fields entry (card fields + email + billing country, which the UCS connector mandates).

  • Regenerates the ilixium enum value into the OpenAPI specs.

Additional fix: connector_order_id on UCS refund / refund-sync requests

Refunds routed through UCS never carried connector_order_id — both
PaymentServiceRefundRequest and RefundServiceGetRequest hardcoded it to None in
crates/router/src/core/unified_connector_service/transformers.rs. Per the proto, that field is
"the connector-side identifier for the original payment that this refund targets".

This is a real, connector-agnostic gap, and it makes refunds impossible for connectors that bind a
refund to the merchant-side reference of the original payment rather than to a gateway-generated
id. Ilixium is one: POST /direct/refund and the POST /history/operations filter used by RSync
are both keyed on the original authorisation's transaction.merchantRef, and Ilixium publishes no
gateway-id lookup. UCS's connector_transaction_id holds Ilixium's gatewayRef (a dashed UUID),
which is not a merchantRef and cannot be converted into one, so the connector refuses locally
with Missing required field: connector_order_id (surfaced as IR_06) rather than sending a
reference that points at nothing.

The fix follows the precedent already established by the Capture and Void paths, which send the
original attempt's stored connector_request_reference_id as merchant_capture_id /
merchant_void_id:

  • Adds RefundsData::payment_connector_request_reference_id, populated in both v1 and v2
    construct_refund_router_data from payment_attempt.connector_request_reference_id (the same
    value the Authorize went out with; core::utils::get_connector_request_reference_id
    short-circuits to the stored value so every leg of a payment reuses it).
  • Sends it as connector_order_id on both the UCS Refund and RSync requests.
  • Relay refunds have no locally recorded payment attempt, so they pass None — unchanged
    behaviour.

This only populates a field that was previously always None, so no other connector's behaviour
changes: connector_order_id is read on the refund/refund-sync path by Ilixium alone (the other
UCS connectors that use it — Razorpay, Easebuzz, PayPal, Cashfree, Airwallex, Affirm, Flywire —
read it on Authorize/CreateOrder, which this PR does not touch).

Scope

Card one-time payments (3DS + no-3DS) plus the Capture / Void / Refund / RSync legs that UCS already implements. No mandates or wallets.

Motivation and Context

Ilixium was implemented in the connector-service (UCS) repo. Hyperswitch could not route to it because the connector name did not exist in the Connector enum and there was no ConnectorSpecificConfig variant to build the x-connector-config header from.

How did you test it?

  • cargo check --workspace with the full v1 feature set — clean
  • cargo check --workspace with the full v2 feature set — clean
  • cargo clippy --workspace --all-targets (v1 features) — clean
  • cargo +nightly fmt --all -- --check — clean
  • Verified ConnectorConfig::get_connector_config(Connector::Ilixium) loads the new SignatureKey dashboard config

End-to-end verified against a mock Ilixium server (no Ilixium sandbox credentials exist yet),
driving Hyperswitch -> UCS -> mock and asserting on the bytes the mock actually received:

  • Authorize (manual capture) -> Capture -> POST /refunds -> refund sync, all succeeded.
  • The mock received POST /platform/ili/direct/refund, and its transaction.merchantRef is
    byte-identical to the merchantRef sent on the original POST /platform/ili/direct/auth — which
    is the whole point of the fix. Before the fix the same flow failed with
    IR_06 Missing required field: connector_order_id.
  • Refund sync reached POST /platform/ili/history/operations and the refund resolved to
    succeeded.
  • x-merchant-digest recomputes correctly from the raw received bytes on every request.
  • Re-ran a no-3DS payment afterwards — still succeeded, no regression.

End-to-end testing is planned against a mock Ilixium server, because no Ilixium sandbox credentials exist yet. Manual verification recipe:

  1. Enable UCS: insert ucs_enabled = "true" into the configs table, and point [grpc_client.unified_connector_service] base_url at a running connector-service.
  2. Create the MCA:
POST /account/{merchant_id}/connectors
{
  "connector_type": "payment_processor",
  "connector_name": "ilixium",
  "connector_account_details": {
    "auth_type": "SignatureKey",
    "api_key":   "<Digest Calculation Password>",
    "key1":      "<MerchantId>",
    "api_secret":"<AccountId>"
  },
  "payment_methods_enabled": [
    { "payment_method": "card",
      "payment_method_types": [
        { "payment_method_type": "credit", "card_networks": ["Visa","Mastercard"], "minimum_amount": 1, "maximum_amount": 68607706, "recurring_enabled": false, "installment_payment_enabled": false },
        { "payment_method_type": "debit",  "card_networks": ["Visa","Mastercard"], "minimum_amount": 1, "maximum_amount": 68607706, "recurring_enabled": false, "installment_payment_enabled": false }
      ] }
  ]
}
  1. Create a payment with "connector": ["ilixium"], card payment method data, email, billing.address.country, and — for 3DS — authentication_type: "three_ds", a return_url and a full browser_info block.

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code

🤖 Generated with Claude Code

Registers Ilixium as a Hyperswitch connector so card payments can be
routed to the Unified Connector Service (UCS), where the actual Ilixium
Direct API integration lives.

- Add `Ilixium` to `common_enums::Connector`, `euclid` `Connector` /
  `RoutableConnectors` and the connector -> routable-connector mappings
- Add a UCS-only connector stub (`hyperswitch_connectors::connectors::Ilixium`)
  so `ConnectorData`/feature-matrix resolution succeeds; the stub only
  validates the `SignatureKey` auth shape
- Add `ConnectorSpecificConfig::Ilixium` so the `x-connector-config`
  header sent to UCS carries the three credentials:
  api_key = Digest Calculation Password, key1 = MerchantId,
  api_secret = AccountId
- Add `ilixium` to `ucs_only_connectors` in development / example /
  env_specific / integration_test configs so it always takes the UCS path
- Add `ilixium.base_url` and dashboard connector config entries

Scope is card one-time Authorize (3DS + no-3DS) only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shuklatushar226
shuklatushar226 requested review from a team as code owners August 13, 2026 18:00
@semanticdiff-com

semanticdiff-com Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/connector.rs  99% smaller
  crates/hyperswitch_connectors/src/connectors.rs  93% smaller
  crates/router/src/core/unified_connector_service/transformers.rs  34% smaller
  crates/hyperswitch_connectors/src/default_implementations.rs  32% smaller
  crates/common_enums/src/connector_enums.rs  26% smaller
  crates/hyperswitch_connectors/src/default_implementations_v2.rs  17% smaller
  api-reference/v1/openapi_spec_v1.json  0% smaller
  api-reference/v2/openapi_spec_v2.json  0% smaller
  config/config.example.toml Unsupported file format
  config/deployments/env_specific.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/connector_configs/src/connector.rs  0% smaller
  crates/connector_configs/toml/development.toml Unsupported file format
  crates/connector_configs/toml/production.toml Unsupported file format
  crates/connector_configs/toml/sandbox.toml Unsupported file format
  crates/euclid/src/enums.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/ilixium.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/ilixium/transformers.rs  0% smaller
  crates/hyperswitch_domain_models/src/connector_endpoints.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types.rs  0% smaller
  crates/payment_methods/src/configs/payment_connector_required_fields.rs  0% smaller
  crates/router/src/core/connector_validation.rs  0% smaller
  crates/router/src/core/relay/utils.rs  0% smaller
  crates/router/src/core/unified_connector_service/connector_config.rs  0% smaller
  crates/router/src/core/utils.rs  0% smaller
  crates/router/src/types/api/connector_mapping.rs  0% smaller
  crates/router/src/types/api/feature_matrix.rs  0% smaller
  crates/router/src/types/connector_transformers.rs  0% smaller
  crates/router/tests/connectors/utils.rs  0% smaller
  loadtest/config/development.toml Unsupported file format

@hyperswitch-bot hyperswitch-bot Bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Aug 13, 2026
…ector_order_id via UCS

Refunds routed through the Unified Connector Service never carried
`connector_order_id`: both `PaymentServiceRefundRequest` (Refund) and
`RefundServiceGetRequest` (RSync) hardcoded it to `None`. The proto defines
that field as "the connector-side identifier for the original payment that this
refund targets", and the only site that ever populated it was CompleteAuthorize.

Connectors that bind a refund to the merchant-side reference of the original
payment — rather than to a gateway-generated id — therefore cannot refund at
all. Ilixium is one: `POST /direct/refund`, and the `POST /history/operations`
filter that RSync uses, are both keyed on the original authorisation's
`transaction.merchantRef`, and no gateway-id lookup is published. UCS's
`connector_transaction_id` holds Ilixium's `gatewayRef` (a dashed UUID), which
is not a `merchantRef` and cannot be converted into one, so the connector
refuses locally with `Missing required field: connector_order_id`, surfaced to
the merchant as `IR_06`.

Follow the precedent already set by the Capture and Void paths, which send the
original attempt's stored `connector_request_reference_id` as
`merchant_capture_id` / `merchant_void_id`:

- add `RefundsData::payment_connector_request_reference_id`, populated in both
  the v1 and v2 `construct_refund_router_data` from
  `payment_attempt.connector_request_reference_id` — the same value the
  Authorize went out with, since `get_connector_request_reference_id`
  short-circuits to the stored value for every subsequent leg of a payment;
- send it as `connector_order_id` on the UCS Refund and RSync requests;
- relay refunds have no locally recorded payment attempt, so they pass `None`,
  which is what they sent before.

This only populates a field that was previously always `None`, so no other
connector's behaviour changes: on the refund and refund-sync path
`connector_order_id` is read by Ilixium alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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 S-test-ready Status: This PR is ready for cypress-tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Integration][P0] Illexium — cards one-time payments

1 participant