juspay/hyperswitch

[BUG]: [BAMBORA] Response Deserialization Issue in PSync when a Manual Capture payment is made

Open

#9379 opened on Sep 15, 2025

View on GitHub
 (8 comments) (0 reactions) (1 assignee)Rust (42,690 stars) (4,676 forks)batch import
RustS-unassignedgood first issuehacktoberfest

Description

Feature Description/Summary

Bambora is a global payment processing platform that enables merchants to accept credit and debit card payments securely across multiple channels (e-commerce, in-store, mobile, etc.). The gateway provides APIs for authorization, capture, settlement, refunds, and reporting.

Context

When a manual capture type payment is made and the status of that payment is requires_capture and if we attempt to make a force PSync call at that time, we get a deserialization error from the connector.

ERROR router::services::api: error: {"error":{"type":"api","message":"Something went wrong","code":"HE_00"}}
├╴at crates/router/src/services/api.rs:737:14
│
├─▶ {"error":{"type":"server_not_available","code":"HE_00","message":"Something went wrong"}}
│   ╰╴at crates/router/src/core/errors/utils.rs:305:17
│
├─▶ Failed to deserialize connector response
│   ╰╴at crates/hyperswitch_connectors/src/connectors/bambora.rs:428:14
│
├─▶ Failed to parse struct: bambora PaymentsResponse
│   ├╴at /Users/sayak.b/Juspay/All-HS/hyperswitch/crates/common_utils/src/ext_traits.rs:175:14
│   ╰╴Unable to parse hyperswitch_connectors::connectors::bambora::transformers::BamboraPaymentsResponse from bytes b"{\"id\":10005916,\"authorizing_merchant_id\":300213193,\"approved\":1,\"message_id\":1,\"message\":\"Approved\",\"auth_code\":\"TEST\",\"created\":\"2025-09-15T06:24:42.7024081-07:00\",\"amount\":25.00,\"order_number\":\"pay_VIi82vNXfsYqduXbOITV_1\",\"type\":\"PA\",\"comments\":\"\",\"batch_number\":\"0256\",\"total_refunds\":0.0,\"total_completions\":0.0,\"payment_method\":\"CC\",\"card\":{\"name\":\"joseph Doe\",\"expiry_month\":\"10\",\"expiry_year\":\"25\",\"card_type\":\"VI\",\"last_four\":\"1234\",\"avs_result\":\"N\",\"cvd_result\":\"1\",\"cavv_result\":\"\"},\"billing\":{\"name\":\"joseph Doe\",\"address_line1\":\"1467\",\"address_line2\":\"Harrison Street\",\"city\":\"San Fransico\",\"province\":\"\",\"country\":\"\",\"postal_code\":\"94122\",\"phone_number\":\"9123456789\",\"email_address\":\"\",\"phone_country_code\":\"\",\"phone_type\":\"m\"},\"shipping\":{\"name\":\"\",\"address_line1\":\"\",\"address_line2\":\"\",\"city\":\"\",\"province\":\"\",\"country\":\"\",\"postal_code\":\"\",\"phone_number\":\"\",\"email_address\":\"\",\"phone_country_code\":\"\"},\"custom\":{\"ref1\":\"\",\"ref2\":\"\",\"ref3\":\"\",\"ref4\":\"\",\"ref5\":\"\"},\"adjusted_by\":[],\"links\":[{\"rel\":\"complete\",\"href\":\"https://api.na.bambora.com/v1/payments/10005916/completions\",\"method\":\"POST\"}],\"device_channel\":\"\"}"
│
╰─▶ unknown variant ``, expected one of `AF`, `AX`, `AL`, `DZ`, `AS`, `AD`, `AO`, `AI`, `AQ`, `AG`, `AR`, `AM`, `AW`, `AU`, `AT`, `AZ`, `BS`, `BH`, `BD`, `BB`, `BY`, `BE`, `BZ`, `BJ`, `BM`, `BT`, `BO`, `BQ`, `BA`, `BW`, `BV`, `BR`, `IO`, `BN`, `BG`, `BF`, `BI`, `KH`, `CM`, `CA`, `CV`, `KY`, `CF`, `TD`, `CL`, `CN`, `CX`, `CC`, `CO`, `KM`, `CG`, `CD`, `CK`, `CR`, `CI`, `HR`, `CU`, `CW`, `CY`, `CZ`, `DK`, `DJ`, `DM`, `DO`, `EC`, `EG`, `SV`, `GQ`, `ER`, `EE`, `ET`, `FK`, `FO`, `FJ`, `FI`, `FR`, `GF`, `PF`, `TF`, `GA`, `GM`, `GE`, `DE`, `GH`, `GI`, `GR`, `GL`, `GD`, `GP`, `GU`, `GT`, `GG`, `GN`, `GW`, `GY`, `HT`, `HM`, `VA`, `HN`, `HK`, `HU`, `IS`, `IN`, `ID`, `IR`, `IQ`, `IE`, `IM`, `IL`, `IT`, `JM`, `JP`, `JE`, `JO`, `KZ`, `KE`, `KI`, `KP`, `KR`, `KW`, `KG`, `LA`, `LV`, `LB`, `LS`, `LR`, `LY`, `LI`, `LT`, `LU`, `MO`, `MK`, `MG`, `MW`, `MY`, `MV`, `ML`, `MT`, `MH`, `MQ`, `MR`, `MU`, `YT`, `MX`, `FM`, `MD`, `MC`, `MN`, `ME`, `MS`, `MA`, `MZ`, `MM`, `NA`, `NR`, `NP`, `NL`, `NC`, `NZ`, `NI`, `NE`, `NG`, `NU`, `NF`, `MP`, `NO`, `OM`, `PK`, `PW`, `PS`, `PA`, `PG`, `PY`, `PE`, `PH`, `PN`, `PL`, `PT`, `PR`, `QA`, `RE`, `RO`, `RU`, `RW`, `BL`, `SH`, `KN`, `LC`, `MF`, `PM`, `VC`, `WS`, `SM`, `ST`, `SA`, `SN`, `RS`, `SC`, `SL`, `SG`, `SX`, `SK`, `SI`, `SB`, `SO`, `ZA`, `GS`, `SS`, `ES`, `LK`, `SD`, `SR`, `SJ`, `SZ`, `SE`, `CH`, `SY`, `TW`, `TJ`, `TZ`, `TH`, `TL`, `TG`, `TK`, `TO`, `TT`, `TN`, `TR`, `TM`, `TC`, `TV`, `UG`, `UA`, `AE`, `GB`, `UM`, `UY`, `UZ`, `VU`, `VE`, `VN`, `VG`, `VI`, `WF`, `EH`, `YE`, `ZM`, `ZW`, `US` at line 1 column 629

This happens because Bambora returns "" (empty string) for certain fields (e.g. billing.country, shipping.country, province, email_address, etc.), but our struct models them as Option. Serde does not treat "" as None by default and instead attempts to parse it into the underlying type (CountryAlpha2), causing the deserialization failure.

Starter Tasks

  • Review Bambora’s API docs and confirm which fields can come back as empty strings ("").
  • Add a serde helper function to map "" → None for these fields.
  • Apply this deserializer to fields in AddressData (e.g., country, province, postal_code, phone_number, email_address) and anywhere else Bambora may return empty values.

Implementation Hints

  • You can define a helper function like empty_string_as_none in transformers.rs.
  • Update AddressData struct with #[serde(default, deserialize_with = "empty_string_as_none")] for affected fields.

Acceptance Criteria

  • Request and Response body added for each of the flows where integrity check is applied.
  • All the required GitHub checks passing
  • Formatted the code using cargo +nightly fmt --all

How to Test it

  • Create a Merchant Account in local
  • Create an API Key
  • Add the connector - Tsys
  • Test out the flows

Mentor Contact

  • Tag @bsayak03 [Sayak Bhattacharya] in the comments if you have any doubts/queries

Resources

Here is the connector documentation link : URL

Pre-Flight

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

  • I checked and didn't find a similar issue

Have you read the Contributing Guidelines?

Submission Process:

  • Ask the maintainers for assignment of the issue, you can request for assignment by commenting on the issue itself.
  • Once assigned, submit a pull request (PR).
  • Maintainers will review and provide feedback, if any.
  • Maintainers can unassign issues due to inactivity, read more here.

Refer here for Terms and conditions for the contest.

Contributor guide