Skip to content

[BUG] connector_mandate_id not returned for Adyen card mandate (CIT) — storePaymentMethod missing from Adyen request #12687

@syedasad912

Description

@syedasad912

Bug Description

Hyperswitch version: v1.123.1-dirty-233117e-2026-05-18
Connector: Adyen
Flow: New mandate creation (CIT) for card
Expected behavior:
When creating a payment with payment_type: new_mandate, setup_future_usage: off_session, and mandate_data.mandate_type.multi_use, Hyperswitch should send storePaymentMethod: true and recurringProcessingModel: CardOnFile to Adyen, and store the returned recurringDetailReference as connector_mandate_id.
Actual behavior:

Adyen request does NOT contain storePaymentMethod or recurringProcessingModel
Adyen response does NOT return recurringDetailReference
Hyperswitch response returns mandate_id: null and connector_mandate_id: null
setup_future_usage in response is always on_session regardless of what is sent in request

Adyen request sent by Hyperswitch:

json{
  "shopperInteraction": "Ecommerce",
  "shopperReference": "merchant_1781003022_cus_oDoJmNHeHbnmAVvHWwEG",
  "additionalData": { "executeThreeD": "false" }
}

storePaymentMethod and recurringProcessingModel are absent.
Payment request DTO used:

json{
  "payment_type": "new_mandate",
  "setup_future_usage": "off_session",
  "off_session": false,
  "mandate_data": {
    "customer_acceptance": {
      "acceptance_type": "online",
      "accepted_at": "2026-06-10T13:10:00Z",
      "online": { "ip_address": "x.x.x.x", "user_agent": "Mozilla/5.0..." }
    },
    "mandate_type": { "multi_use": { "amount": 0, "currency": "USD" } }
  }
}

Config: adyen is present in mandates.supported_payment_methods for both card.credit and card.debit.
Question: What is the correct way to trigger storePaymentMethod: true in the Adyen request through Hyperswitch for a new mandate CIT flow? Is there a specific field or config missing?

Expected Behavior

Here's the expected behavior section:

Expected Behavior:

  1. Hyperswitch should send the following to Adyen:
json{
  "amount": { "currency": "USD", "value": 6540 },
  "merchantAccount": "<merchant_account>",
  "paymentMethod": { "type": "scheme", "number": "***", "expiryMonth": "***", "expiryYear": "***", "cvc": "***" },
  "reference": "pay_xxx_1",
  "shopperReference": "merchant_xxx_cus_xxx",
  "shopperInteraction": "Ecommerce",
  "storePaymentMethod": true,
  "recurringProcessingModel": "CardOnFile"
}
  1. Adyen should respond with a recurringDetailReference:
json{
  "resultCode": "Authorised",
  "pspReference": "XXXXXXXXXXXXXXXX",
  "additionalData": {
    "recurring.recurringDetailReference": "9916272248971342",
    "recurring.shopperReference": "merchant_xxx_cus_xxx"
  }
}
  1. Hyperswitch payment response should return:
json{
  "payment_id": "pay_xxx",
  "status": "succeeded",
  "setup_future_usage": "off_session",
  "mandate_id": "man_xxx",
  "connector_mandate_id": "9916272248971342",
  "customer_id": "cus_xxx"
}
  1. Subsequent MIT charge using the mandate should work:
    POST /payments
{
  "amount": 1000,
  "currency": "USD",
  "confirm": true,
  "customer_id": "cus_xxx",
  "mandate_id": "man_xxx",
  "off_session": true
}

And Hyperswitch should send to Adyen:

json{
  "shopperInteraction": "ContAuth",
  "recurringProcessingModel": "CardOnFile",
  "paymentMethod": {
    "type": "scheme",
    "storedPaymentMethodId": "9916272248971342"
  }
}

This covers the full CIT → MIT flow that is currently broken.

Actual Behavior

Here's the actual behavior section:

Actual Behavior:

  1. Hyperswitch sends to Adyen (missing recurring fields):
json{
  "amount": { "currency": "USD", "value": 6540 },
  "merchantAccount": "AkhyarFoundationLimitedECOM",
  "paymentMethod": { "type": "scheme", "number": "***", "expiryMonth": "***", "expiryYear": "***", "cvc": "***" },
  "reference": "pay_D5GtUkbSRY7aKfZhXkCn_1",
  "returnUrl": "https://dev-api-hyperswitch.g14n.net/payments/pay_D5GtUkbSRY7aKfZhXkCn/merchant_1781003022/redirect/response/adyen",
  "browserInfo": { "userAgent": "...", "acceptHeader": "...", "language": "en-US", "colorDepth": 24, "screenHeight": 1080, "screenWidth": 1920, "timeZoneOffset": 330, "javaEnabled": false },
  "shopperInteraction": "Ecommerce",
  "shopperReference": "merchant_1781003022_cus_oDoJmNHeHbnmAVvHWwEG",
  "shopperName": { "firstName": "***", "lastName": "***" },
  "shopperLocale": "en",
  "additionalData": { "executeThreeD": "false" }
}

❌ storePaymentMethod is absent
❌ recurringProcessingModel is absent
2. Adyen responds without any recurring token:

json{
  "resultCode": "Authorised",
  "pspReference": "BC8Z3ZZ28CP52775",
  "amount": { "currency": "USD", "value": 6540 },
  "merchantReference": "pay_D5GtUkbSRY7aKfZhXkCn_1",
  "additionalData": {
    "paymentMethod": "visa",
    "networkTxReference": "***",
    "isCardCommercial": "***",
    "scaExemptionRequested": "***"
  }
}

❌ No recurring.recurringDetailReference in additionalData
❌ No card stored in Adyen vault
3. Hyperswitch payment response:

json{
  "payment_id": "pay_D5GtUkbSRY7aKfZhXkCn",
  "status": "succeeded",
  "setup_future_usage": "on_session",
  "mandate_id": null,
  "connector_mandate_id": null,
  "network_transaction_id": "601588850742073"
}

❌ mandate_id is null
❌ connector_mandate_id is null
❌ setup_future_usage is on_session despite sending off_session in request
4. Attempted workarounds that did not work:

Adding payment_type: "new_mandate" → no effect
Adding is_stored_credential: true → field ignored
Adding connector_metadata.adyen.store_payment_method: true → field not passed through to Adyen, stripped from request
mandate_data.mandate_type.multi_use with amount: 0 → no effect

Summary: Hyperswitch is not translating the new mandate intent into Adyen-specific recurring fields (storePaymentMethod, recurringProcessingModel) regardless of what combination of fields is sent in the payment request.

Steps To Reproduce

Here are the exact reproduction steps:

Steps to Reproduce:

  1. Create a customer:
    POST /customers
{
  "name": "Test User",
  "email": "test@example.com"
}
  1. Configure Adyen connector with recurring_enabled: true for card credit/debit in payment_methods_enabled.
  2. Ensure mandates.supported_payment_methods in config has adyen listed under card.credit and card.debit (already present in default config).
  3. Create a payment with new mandate intent:
    POST /payments
{
  "amount": 6540,
  "currency": "USD",
  "confirm": true,
  "connector": ["adyen"],
  "customer_id": "<customer_id>",
  "payment_type": "new_mandate",
  "setup_future_usage": "off_session",
  "off_session": false,
  "mandate_data": {
    "customer_acceptance": {
      "acceptance_type": "online",
      "accepted_at": "2026-06-10T13:10:00Z",
      "online": {
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0"
      }
    },
    "mandate_type": {
      "multi_use": {
        "amount": 0,
        "currency": "USD"
      }
    }
  },
  "payment_method": "card",
  "payment_method_data": {
    "card": {
      "card_number": "4111111111111111",
      "card_exp_month": "03",
      "card_exp_year": "30",
      "card_holder_name": "Test User",
      "card_cvc": "737"
    }
  }
}
  1. Observe the Hyperswitch response:

mandate_id is null
connector_mandate_id is null
setup_future_usage is on_session (overridden from off_session)

  1. Observe the Adyen request sent by Hyperswitch (visible in Adyen dashboard under Developers → API logs):

storePaymentMethod field is absent
recurringProcessingModel field is absent
Only shopperReference is sent, which is not sufficient for Adyen to store the card

  1. Observe the Adyen response:

No recurringDetailReference in additionalData
No card stored in Adyen's token vault

Expected at step 5: mandate_id and connector_mandate_id should be populated.
Expected at step 6: Request should contain storePaymentMethod: true and recurringProcessingModel: "CardOnFile".

Context For The Bug

No response

Environment

Are you using hyperswitch hosted version? Yes/No
If yes, please provide the value of the x-request-id response header to help us debug your issue.

If not (or if building/running locally), please provide the following details:

  1. Operating System or Linux distribution:
  2. Rust version (output of rustc --version): ``
  3. App version (output of cargo r --features vergen -- --version): ``

Have you spent some time checking if this bug has been raised before?

  • I checked and didn't find a similar issue

Have you read the Contributing Guidelines?

Are you willing to submit a PR?

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: BugS-awaiting-triageStatus: New issues that have not been assessed yet

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions