Skip to content

Conversation

@siaass842
Copy link
Contributor

Description

Motivation and Context

Additional Changes

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

How did you test it?

@siaass842 siaass842 requested review from a team as code owners November 12, 2025 06:45
Copy link
Collaborator

@Shubhodip900 Shubhodip900 left a comment

Choose a reason for hiding this comment

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

Add end to end tests and resolve the conflicts.

let connector_meta = if value.connector_metadata.is_empty() {
None
} else {
Some(serde_json::to_value(&value.connector_metadata).unwrap_or_default())
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we are checking whether the connector_metadata value is present or not then why we need unwrap_or_default? We can handle this in a better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Serialization errors now bubble up instead of being silently converted to null

let connector_meta = (!value.connector_metadata.is_empty())
            .then(|| serde_json::to_value(&value.connector_metadata))
            .transpose()
            .map_err(|_| {
                error_stack::report!(ApplicationErrorResponse::InvalidDataFormat {
                    field_name: "connector_metadata".to_string(),
                })
            })?;

);
});
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why we need this changes ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

need to implement ca_certificate

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we handle this in better way so that we can avoid early return.

// connector_flow::{
// Accept, Authorize, Capture, CreateOrder, DefendDispute, PSync, RSync, Refund,
// RepeatPayment, SetupMandate, SubmitEvidence, Void, CreateSessionToken,
// },
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove the commented imports.

// PaymentsAuthorizeData, PaymentsCaptureData, PaymentsResponseData, PaymentsSyncData,
// RefundFlowData, RefundSyncData, RefundsData, RefundsResponseData, RepeatPaymentData,
// SetupMandateRequestData, SubmitEvidenceData, SessionTokenRequestData, SessionTokenResponseData,
// },
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1

// State Information
optional ConnectorState state = 3; // State data for access token storage and other connector-specific state

map<string, string> connector_metadata = 7;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this is added ?

ACI = 1;
ADYEN = 2;
AIRWALLEX = 3;
ARCHIPEL = 90;
Copy link
Contributor

Choose a reason for hiding this comment

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

this is not needed

res: Response,
_event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
// TODO: Implement proper error response parsing
Copy link
Contributor

Choose a reason for hiding this comment

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

where is the error response mapping done

#[serde(rename_all = "camelCase")]
pub struct ArchipelOrderRequest {
amount: MinorUnit,
currency: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

we can use an enum already present

Comment on lines 1133 to 1136
message: error_message
.description
.clone()
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
Copy link
Contributor

Choose a reason for hiding this comment

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

error mapping needs to be done

);
});
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we handle this in better way so that we can avoid early return.

Comment on lines 484 to 488
amount: Option<i64>,
currency: Option<Currency>,
captured_amount: Option<i64>,
authorized_amount: Option<i64>,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
amount: Option<i64>,
currency: Option<Currency>,
captured_amount: Option<i64>,
authorized_amount: Option<i64>,
}
amount: Option<MinorUnit>,
currency: Option<Currency>,
captured_amount: Option<MinorUnit>,
authorized_amount: Option<MinorUnit>,
}

@siaass842 siaass842 added the coderabbit-ai-review Trigger CodeRabbit review label Nov 21, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 21, 2025

📝 Walkthrough

Walkthrough

Adds a new Archipel payment connector module with transformers, extensive flow implementations (authorize, capture, void, refund, sync, mandate, disputes, sessions, tokens), CA certificate support in connector requests, protobuf and domain updates, and configuration entries for Archipel endpoints across environments.

Changes

Cohort / File(s) Summary
Archipel connector module
backend/connector-integration/src/connectors.rs, backend/connector-integration/src/connectors/archipel.rs
Adds public archipel module and re-exports Archipel; implements Connector traits and per-flow ConnectorIntegrationV2/SourceVerification/ConnectorCommon wiring, header/URL/CA helpers, and BASE64_ENGINE.
Archipel transformers
backend/connector-integration/src/connectors/archipel/transformers.rs
Adds comprehensive transformers: request/response models, card/3DS/billing/tenant/config types, TryFrom/From conversions, error types, status mappings, and flow-specific request/response structs for multiple payment flows.
Connector factory & types
backend/connector-integration/src/types.rs, backend/domain_types/src/connector_types.rs
Registers Archipel in connector imports and factory: adds ConnectorEnum::Archipel and maps gRPC enum to Self::Archipel.
Domain types & address
backend/domain_types/src/types.rs, backend/domain_types/src/payment_address.rs
Adds archipel field to Connectors; wires connector_meta into PaymentsSyncData and PaymentsAuthorizeData; adds get_optional_zip() to AddressDetails.
TLS / HTTP client
backend/external-services/src/service.rs, backend/interfaces/src/connector_integration_v2.rs
Extends create_client() to accept ca_certificate and implements mutual/one-way TLS handling; adds get_ca_certificate() to ConnectorIntegrationV2 and includes CA PEM in request building.
gRPC/proto changes
backend/grpc-api-types/proto/payment.proto
Adds ARCHIPEL = 95 to Connector enum and adds map<string,string> connector_metadata to PaymentServiceGetRequest.
Configuration
config/development.toml, config/production.toml, config/sandbox.toml
Adds archipel.base_url entries set to "https://{{merchant_endpoint_prefix}}/ArchiPEL/Transaction/v1" in all environment configs.

Pre-merge checks

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.45% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description is incomplete with only the template structure and no substantive details, motivation, or testing information provided by the author. Complete the PR description by filling in the 'Description', 'Motivation and Context', and 'How did you test it?' sections with specific details about the changes and testing approach.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(connector): add archipel integration flows' clearly and specifically describes the main change: adding a new Archipel payment connector with its integration flows.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (7)
config/sandbox.toml (1)

57-57: LGTM! Configuration follows established patterns.

The Archipel base URL configuration is correctly added. Note: The identical URL across all environments has been flagged for verification in the development.toml review.

backend/domain_types/src/types.rs (1)

2303-2363: Connector metadata → connector_meta serialization is sound; optional simplification

The new connector_meta wiring for PaymentServiceGetRequest (sync) looks correct and the BadRequest on JSON serialization failure is a reasonable choice for client-supplied data. If you want to reduce complexity and align with other flows (e.g. where you directly build a serde_json::Value::Object from a HashMap<String, String> instead of going via serde_json::to_value + .transpose()), you could adopt the same pattern here; that would also remove an effectively unreachable error branch. This is purely a style/consistency tweak, not a functional issue.

backend/connector-integration/src/connectors/archipel/transformers.rs (4)

480-488: Use MinorUnit for amounts in ArchipelOrderResponse instead of raw i64

ArchipelOrderResponse currently models amounts as:

pub struct ArchipelOrderResponse {
    id: String,
    amount: Option<i64>,
    currency: Option<Currency>,
    captured_amount: Option<i64>,
    authorized_amount: Option<i64>,
}

Given the rest of the connector uses MinorUnit for monetary values, it would be more consistent and type‑safe to store these as Option<MinorUnit> instead of Option<i64>. That matches the common pattern in other connectors and avoids accidental unit mismatches.

This also aligns with the earlier suggestion noted in prior reviews.


1121-1143: Archipel‑specific error mapping looks good

The From<ArchipelErrorMessageWithHttpCode> for ErrorResponse implementation correctly:

  • propagates HTTP status,
  • maps Archipel error code and description into code, message, and reason,
  • falls back to NO_ERROR_MESSAGE when description is missing.

This addresses the earlier feedback about adding proper error response mapping for Archipel.


83-111: Remove print! debugging around connector metadata and use structured, redacted logging

Both to_connector_meta (Lines 83–111) and ArchipelRefundRequest::try_from (Lines 1211–1213) use print! to dump full connector metadata. This is unsafe for production: these values can contain tenant‑specific URLs, IDs, and potentially secrets, and printing them directly to stdout is hard to control or redact.

Suggested changes:

  • Remove these print! calls entirely, or
  • Replace them with tracing::debug!/tracing::info! using appropriately redacted fields if you truly need them for diagnostics.

While touching this code, you could also consider using change_context when mapping serde_json::from_str failures in to_connector_meta so that parse errors carry clearer context instead of being flattened.

Also applies to: 1211-1213


1188-1222: Refund metadata handling: avoid print! and consider reusing to_connector_meta semantics

ArchipelRefundRequest::try_from prints the entire connector_metadata and then calls ArchipelConfigData::try_from(&item.router_data.request.connector_metadata)?;.

Two points:

  • As with to_connector_meta, the print! leaks potentially sensitive configuration and should be removed or replaced with structured, redacted logging.
  • Since ArchipelConfigData::try_from already centralizes how metadata is parsed (string vs object with connector_meta_data), reusing that consistently across flows keeps refund behavior aligned with authorize/void/setup‑mandate. If there are refund‑specific formats, it may be cleaner to document them explicitly in to_connector_meta rather than sprinkling assumptions across flows.
backend/connector-integration/src/connectors/archipel.rs (1)

683-699: Remove println!/print! debug statements and avoid leaking connector metadata

There are raw println!/print! calls in:

  • Authorize get_url (Line 691) and
  • PSync get_url (Lines 733–735),

which will emit connector metadata (including connector_meta) directly to stdout. This is noisy in production and can leak sensitive information.

Please remove these and, if you need diagnostics, use structured logging (tracing::debug! / tracing::info!) with appropriate redaction, or rely on existing connector logs.

Also applies to: 731-751

🧹 Nitpick comments (6)
backend/external-services/src/service.rs (1)

727-773: Clarify mutual‑TLS behavior and tighten CA‑based client construction

The branching is clear, but a few details are worth tightening up:

  • When both client_certificate and client_certificate_key are present you immediately fall back to get_base_client, i.e. there is still no actual mutual TLS. That preserves previous behavior but is surprising given the parameter names. Consider either:
    • Implementing mutual TLS here using the existing (commented) helpers, or
    • Returning a configuration error (or at least emitting a structured log/TODO) instead of silently ignoring the certs.
  • If only one of client_certificate or client_certificate_key is set, the code falls through to the default client with no log. Emitting a warning in this misconfiguration case would make debugging easier.
  • The CA path largely duplicates load_custom_ca_certificate_from_content and additionally calls .use_rustls_tls(), which means this branch may use a different TLS backend than the base clients. If that difference is not intentional, consider:
    • Refactoring to reuse load_custom_ca_certificate_from_content (or a small shared helper) for adding root CAs, and
    • Aligning TLS backend usage between the CA and non‑CA paths, or documenting why the CA path must be rustls‑only.

These are all behavioral clarifications / polish rather than blockers, but tightening them now will avoid surprises when mTLS or connector‑specific CAs are rolled out more broadly.

backend/grpc-api-types/proto/payment.proto (1)

1261-1262: Add documentation comment for the new connector_metadata field.

The field is correctly typed and numbered, and its presence is consistent with similar fields in PaymentServiceAuthorizeResponse (line 1221), PaymentServiceVoidRequest (line 1334), and PaymentServiceCaptureRequest (line 1379). However, unlike most fields in this proto file, it lacks an explanatory comment describing its purpose. Adding a brief comment would improve consistency and clarity.

For example:

  // Connector-specific metadata to be used during payment synchronization
  map<string, string> connector_metadata = 7;
backend/domain_types/src/types.rs (1)

94-129: Archipel connector field wiring looks correct; verify config coverage

The new pub archipel: ConnectorParams field is consistent with other connectors and will deserialize from the same config shape. Because this is a non-optional field on a deserialized struct, make sure all deployed configs (all envs) define an archipel block; otherwise startup/deserialization can fail when rolling this out.

backend/connector-integration/src/connectors/archipel.rs (2)

640-657: build_error_response is a generic stub despite having Archipel‑specific error mapping

You now have a dedicated ArchipelErrorMessageWithHttpCode -> ErrorResponse mapping in transformers.rs, and all happy‑path error cases from Archipel responses are handled there. This build_error_response still drops the response body and returns NO_ERROR_CODE/NO_ERROR_MESSAGE, which will be used for transport/parse failures.

Consider either:

  • delegating to a connector‑specific parser (parsing the body into ArchipelErrorMessage when possible), or
  • at least enriching reason/message with the raw body to aid debugging, instead of the generic placeholders.

This will make error reporting more actionable if we ever fall back to build_error_response.


731-751: PSync connector_meta parsing is stringly and fragile; consider simplifying

PSync get_url assumes connector_meta is:

  • present,
  • an object with a "connector_meta_data" field,
  • whose value is a JSON string encoding ArchipelTransactionMetadata.

This double‑encoding (Value → nested string → serde_json::from_str) is brittle and tightly couples URL building to a specific metadata shape. A simpler and less error‑prone approach would be to:

  • store ArchipelTransactionMetadata directly as a Value (or dedicated metadata type), and
  • deserialize via serde_json::from_value / an internal helper, instead of going through a nested string.

Also, using MissingConnectorTransactionID when connector_meta is absent conflates two different issues (missing metadata vs missing transaction ID). A more precise error (e.g., NoConnectorMetaData or MissingRequiredField { field_name: "connector_meta" }) would make failures easier to debug.

backend/connector-integration/src/connectors/archipel/transformers.rs (1)

296-334: Avoid serde_json::to_string(..).unwrap_or_default() to derive PAN for issuer detection

In ArchipelCard::try_from you compute:

let raw_card = serde_json::to_string(&ccard.card_number.0)
    .unwrap_or_default()
    .trim_matches('"')
    .to_string();
let card_issuer = domain_types::utils::get_card_issuer(&raw_card).ok();

Concerns:

  • unwrap_or_default() silently turns any serialization failure into an empty string, which then yields card_issuer = None and ArchipelCardScheme::Unknown, hiding real issues.
  • Going through JSON and trimming quotes is brittle; it depends on how the secret type chooses to serialize.

A safer approach is to:

  • use the masking crate’s expose/peek API (or an equivalent helper on RawCardNumber<T>) to get the underlying PAN as a string, and
  • propagate serialization/extraction errors instead of defaulting to empty.

This keeps issuer detection deterministic and avoids silently masking real data issues.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb39ef3 and 30e8c34.

📒 Files selected for processing (14)
  • backend/connector-integration/src/connectors.rs (1 hunks)
  • backend/connector-integration/src/connectors/archipel.rs (1 hunks)
  • backend/connector-integration/src/connectors/archipel/transformers.rs (1 hunks)
  • backend/connector-integration/src/types.rs (2 hunks)
  • backend/domain_types/src/connector_types.rs (2 hunks)
  • backend/domain_types/src/payment_address.rs (1 hunks)
  • backend/domain_types/src/types.rs (2 hunks)
  • backend/external-services/src/service.rs (2 hunks)
  • backend/grpc-api-types/proto/payment.proto (2 hunks)
  • backend/interfaces/src/connector_integration_v2.rs (2 hunks)
  • config/development.toml (1 hunks)
  • config/production.toml (1 hunks)
  • config/sandbox.toml (1 hunks)
  • examples/example-hs-grpc/proto/payment.proto (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-10-13T07:57:48.659Z
Learnt from: iemyashasvi
Repo: juspay/connector-service PR: 194
File: config/development.toml:62-63
Timestamp: 2025-10-13T07:57:48.659Z
Learning: For Worldpay Vantiv development environment in config/development.toml, the correct URLs are:
- base_url: "https://transact.vantivprelive.com/vap/communicator/online"
- secondary_base_url: "https://onlinessr.vantivprelive.com"

Applied to files:

  • config/production.toml
  • config/development.toml
  • config/sandbox.toml
📚 Learning: 2025-10-13T08:02:24.195Z
Learnt from: iemyashasvi
Repo: juspay/connector-service PR: 194
File: config/sandbox.toml:54-55
Timestamp: 2025-10-13T08:02:24.195Z
Learning: For Worldpay Vantiv sandbox environment in config/sandbox.toml, the correct URLs are:
- base_url: "https://www.testvantivcnp.com/sandbox/new/sandbox/communicator/online"
- secondary_base_url: "https://www.testvantivcnp.com/sandbox"

Applied to files:

  • config/production.toml
  • config/development.toml
  • config/sandbox.toml
📚 Learning: 2025-09-26T08:08:52.624Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 193
File: backend/connector-integration/src/connectors/rapyd/transformers.rs:505-524
Timestamp: 2025-09-26T08:08:52.624Z
Learning: In Rapyd connector (backend/connector-integration/src/connectors/rapyd/transformers.rs), the next_action field in ResponseData struct is required (not Optional) as per Rapyd API documentation. This field always appears in payment responses with values like "3d_verification", "pending_capture", "pending_confirmation", or "not_applicable", consistent with hyperswitch connector patterns.

Applied to files:

  • backend/grpc-api-types/proto/payment.proto
  • backend/domain_types/src/types.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-24T08:45:31.195Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments.rs:306-315
Timestamp: 2025-09-24T08:45:31.195Z
Learning: In Peachpayments connector (backend/connector-integration/src/connectors/peachpayments.rs), the connector_transaction_id field has different types across flows: PaymentVoidData uses String directly, while PaymentsCaptureData uses ResponseId enum that requires pattern matching or get_connector_transaction_id() method.

Applied to files:

  • backend/domain_types/src/connector_types.rs
  • backend/domain_types/src/types.rs
  • backend/connector-integration/src/types.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
  • backend/connector-integration/src/connectors/archipel.rs
📚 Learning: 2025-09-15T06:56:22.535Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/connector-integration/src/connectors/trustpay.rs:747-762
Timestamp: 2025-09-15T06:56:22.535Z
Learning: In Trustpay connector (backend/connector-integration/src/connectors/trustpay.rs), the refund_connector_metadata field has different data formats in different contexts: RSync expects it to be already parsed as JSON Value (accessing directly with .get()), while other refund flows expect it to be a JSON string that needs serde_json::from_str() parsing. The extract_payment_method_from_refund_metadata helper is designed for the latter case and should not be used in RSync.

Applied to files:

  • backend/domain_types/src/connector_types.rs
  • backend/domain_types/src/types.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
  • backend/connector-integration/src/connectors/archipel.rs
📚 Learning: 2025-09-24T10:18:33.115Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments/transformers.rs:50-56
Timestamp: 2025-09-24T10:18:33.115Z
Learning: In Peach Payments connector API (backend/connector-integration/src/connectors/peachpayments/transformers.rs), the authorize request struct uses the field "charge_method" as expected by the Peach Payments API, not "paymentType" or other variations.

Applied to files:

  • backend/domain_types/src/types.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
  • backend/connector-integration/src/connectors/archipel.rs
🧬 Code graph analysis (2)
backend/connector-integration/src/connectors/archipel/transformers.rs (2)
backend/connector-integration/src/connectors/macros.rs (1)
  • router_data (94-105)
backend/domain_types/src/connector_types.rs (3)
  • from (2216-2412)
  • to_connector_meta (681-688)
  • std (686-686)
backend/connector-integration/src/connectors/archipel.rs (3)
backend/connector-integration/src/connectors/macros.rs (2)
  • router_data (94-105)
  • request_body (66-75)
backend/interfaces/src/connector_integration_v2.rs (5)
  • get_content_type (59-61)
  • get_error_response_v2 (136-145)
  • get_headers (51-56)
  • get_url (69-76)
  • get_ca_certificate (213-221)
backend/connector-integration/src/connectors/archipel/transformers.rs (16)
  • try_from (59-66)
  • try_from (77-80)
  • try_from (301-333)
  • try_from (403-436)
  • try_from (619-630)
  • try_from (643-684)
  • try_from (694-788)
  • try_from (812-865)
  • try_from (890-952)
  • try_from (960-1009)
  • try_from (1048-1064)
  • try_from (1077-1118)
  • try_from (1205-1222)
  • try_from (1235-1256)
  • try_from (1282-1303)
  • try_from (1350-1443)
🔇 Additional comments (13)
backend/domain_types/src/payment_address.rs (1)

311-313: New get_optional_zip accessor is consistent and safe

get_optional_zip mirrors the existing optional accessors (get_optional_line2, names, etc.), correctly cloning Option<Secret<String>> and introducing no behavior change. Looks good as an additional helper.

backend/external-services/src/service.rs (1)

665-681: Wiring ca_certificate into create_client looks correct and side‑effect free

Passing request.ca_certificate through to create_client cleanly extends the API without altering existing behavior when the field is None. No issues from this call site as long as upstream code only populates ca_certificate when a valid PEM is available.

config/production.toml (1)

57-57: LGTM! Configuration follows established patterns.

The Archipel base URL configuration is correctly added and follows the same templated pattern used by other connectors like Adyen. The {{merchant_endpoint_prefix}} placeholder enables environment-aware endpoint construction as described in the AI summary.

backend/interfaces/src/connector_integration_v2.rs (2)

212-221: LGTM! CA certificate support properly integrated.

The new get_ca_certificate method follows the established pattern of get_certificate and get_certificate_key, enabling one-way TLS verification. The default implementation safely returns None, allowing connectors to opt-in as needed.


108-108: LGTM! CA certificate correctly wired into request builder.

The CA certificate is properly integrated into the request building flow, positioned after the mutual TLS certificate/key setup.

backend/connector-integration/src/connectors.rs (1)

92-93: LGTM! Standard connector module integration.

The Archipel module is correctly declared and exported, following the established pattern used by all other connectors in this file.

backend/domain_types/src/connector_types.rs (2)

76-76: LGTM! Archipel correctly added to ConnectorEnum.

The Archipel variant is properly added to the enum, maintaining consistency with the codebase's connector registry pattern.


115-115: LGTM! gRPC mapping correctly implemented.

The mapping from the gRPC Connector enum to the internal ConnectorEnum is properly implemented for Archipel.

backend/connector-integration/src/types.rs (2)

7-7: LGTM! Import correctly added.

The Archipel import is properly included alongside other connector imports.


63-63: LGTM! Connector instantiation correctly implemented.

The Archipel connector is properly instantiated in the convert_connector match, following the established pattern of Box::new(Archipel::new()).

config/development.toml (1)

65-65: Archipel identical URLs are intentional and correctly configured.

Verification confirms the identical Archipel base URLs across development, sandbox, and production are an intentional design choice. The configuration uses placeholder substitution ({{merchant_endpoint_prefix}}), where the actual endpoint differentiation occurs at runtime when the merchant_endpoint_prefix value is injected per environment. This is a valid architectural pattern used similarly by other connectors (e.g., Adyen).

backend/grpc-api-types/proto/payment.proto (1)

459-459: ARCHIPEL connector type added to enum.

The new ARCHIPEL = 95 enum value is properly positioned and follows the sequential naming convention established in the codebase. This integrates with the broader Archipel connector integration outlined in the PR.

backend/connector-integration/src/connectors/archipel.rs (1)

926-941: Add build_env_specific_endpoint call to RSync's get_url method to ensure merchant endpoint prefix substitution is applied consistently with other flows

The verification confirms your concern. RSync (lines 926-941) uniquely bypasses build_env_specific_endpoint, while all other flows—Refund, PSync, Capture, Void, and SetupMandate—use it to substitute the {{merchant_endpoint_prefix}} placeholder. The build_env_specific_endpoint function explicitly replaces this placeholder with the actual endpoint prefix from connector metadata.

RSync should call build_env_specific_endpoint with req.request.connector_metadata (following the same pattern as the Refund flow at line 884-885), or the base URL must be guaranteed to be fully expanded without placeholders in configuration. Without this fix, refund sync will fail in multi-tenant deployments requiring merchant-specific endpoint prefixes.

⛔ Skipped due to learnings
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/connector-integration/src/connectors/trustpay.rs:747-762
Timestamp: 2025-09-15T06:56:22.535Z
Learning: In Trustpay connector (backend/connector-integration/src/connectors/trustpay.rs), the refund_connector_metadata field has different data formats in different contexts: RSync expects it to be already parsed as JSON Value (accessing directly with .get()), while other refund flows expect it to be a JSON string that needs serde_json::from_str() parsing. The extract_payment_method_from_refund_metadata helper is designed for the latter case and should not be used in RSync.
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 95
File: backend/connector-integration/src/connectors/noon.rs:0-0
Timestamp: 2025-08-06T08:45:01.878Z
Learning: In the Noon connector, connector_refund_id is populated from API responses and is already validated upstream. The field cannot be empty due to struct constraints, and special URL characters like '/', '?', '#', '&' will never appear since the IDs come from Noon's API responses which follow their alphanumeric format.

ACI = 1;
ADYEN = 2;
AIRWALLEX = 3;
ARCHIPEL = 90;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify enum value consistency across proto files.

There's a discrepancy: this file uses ARCHIPEL = 90, but according to the AI summary, backend/grpc-api-types/proto/payment.proto uses ARCHIPEL = 95. Proto enum values should be consistent across all proto files to avoid serialization issues.

Additionally, a past review comment on this line stated "this is not needed" – please clarify whether this example proto should include the ARCHIPEL enum value.


🏁 Script executed:

#!/bin/bash
# Verify ARCHIPEL enum values across all proto files
rg -n "ARCHIPEL\s*=\s*\d+" --type proto

Length of output: 29



🏁 Script executed:

#!/bin/bash
# Find all proto files and search for ARCHIPEL enum values
echo "=== Finding all .proto files ==="
fd -e proto

echo -e "\n=== Searching for ARCHIPEL in all proto files ==="
rg -n "ARCHIPEL" -g "*.proto"

echo -e "\n=== Checking payment.proto files specifically ==="
find . -name "payment.proto" -type f | head -20

Length of output: 587



🏁 Script executed:

#!/bin/bash
# Check context around ARCHIPEL in both files
echo "=== Context around ARCHIPEL in examples/example-hs-grpc/proto/payment.proto (lines 110-130) ==="
sed -n '110,130p' examples/example-hs-grpc/proto/payment.proto

echo -e "\n=== Context around ARCHIPEL in backend/grpc-api-types/proto/payment.proto (lines 450-470) ==="
sed -n '450,470p' backend/grpc-api-types/proto/payment.proto

echo -e "\n=== Check if these are in the same enum and its name ==="
echo "Example file enum:"
sed -n '100,130p' examples/example-hs-grpc/proto/payment.proto | grep -A5 -B5 "enum"

echo -e "\nBackend file enum:"
sed -n '440,470p' backend/grpc-api-types/proto/payment.proto | grep -A5 -B5 "enum"

Length of output: 1367


Fix enum value mismatch for ARCHIPEL in Connector enum.

The ARCHIPEL enum value is inconsistent across proto files:

  • examples/example-hs-grpc/proto/payment.proto:121 uses ARCHIPEL = 90
  • backend/grpc-api-types/proto/payment.proto:459 uses ARCHIPEL = 95

Both define the same Connector enum. Mismatched enum values will cause serialization incompatibility and prevent gRPC interoperability between the example code and the actual backend. Update the example proto file to use ARCHIPEL = 95 to match the backend definition.

🤖 Prompt for AI Agents
In examples/example-hs-grpc/proto/payment.proto around line 121, the Connector
enum value ARCHIPEL is set to 90 but the backend definition uses 95; change the
enum value for ARCHIPEL to 95 in this example proto so it matches
backend/grpc-api-types/proto/payment.proto and ensure both proto files use
identical numeric values for the Connector enum to avoid serialization
incompatibility.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30e8c34 and 4364e18.

📒 Files selected for processing (6)
  • backend/connector-integration/src/connectors.rs (1 hunks)
  • backend/connector-integration/src/connectors/archipel.rs (1 hunks)
  • backend/connector-integration/src/connectors/archipel/transformers.rs (1 hunks)
  • backend/connector-integration/src/types.rs (2 hunks)
  • backend/domain_types/src/types.rs (2 hunks)
  • backend/external-services/src/service.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/connector-integration/src/connectors.rs
  • backend/domain_types/src/types.rs
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-24T08:45:31.195Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments.rs:306-315
Timestamp: 2025-09-24T08:45:31.195Z
Learning: In Peachpayments connector (backend/connector-integration/src/connectors/peachpayments.rs), the connector_transaction_id field has different types across flows: PaymentVoidData uses String directly, while PaymentsCaptureData uses ResponseId enum that requires pattern matching or get_connector_transaction_id() method.

Applied to files:

  • backend/connector-integration/src/types.rs
  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-15T04:33:18.323Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/grpc-server/tests/trustpay_payment_flows_test.rs:1-4
Timestamp: 2025-09-15T04:33:18.323Z
Learning: In test files for the juspay/connector-service repository, broad Clippy suppressions (#![allow(clippy::expect_used)], #![allow(clippy::unwrap_used)], #![allow(clippy::panic)]) are used as an established coding convention, as confirmed by the maintainer.

Applied to files:

  • backend/connector-integration/src/types.rs
📚 Learning: 2025-09-15T06:56:22.535Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/connector-integration/src/connectors/trustpay.rs:747-762
Timestamp: 2025-09-15T06:56:22.535Z
Learning: In Trustpay connector (backend/connector-integration/src/connectors/trustpay.rs), the refund_connector_metadata field has different data formats in different contexts: RSync expects it to be already parsed as JSON Value (accessing directly with .get()), while other refund flows expect it to be a JSON string that needs serde_json::from_str() parsing. The extract_payment_method_from_refund_metadata helper is designed for the latter case and should not be used in RSync.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-24T10:18:33.115Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments/transformers.rs:50-56
Timestamp: 2025-09-24T10:18:33.115Z
Learning: In Peach Payments connector API (backend/connector-integration/src/connectors/peachpayments/transformers.rs), the authorize request struct uses the field "charge_method" as expected by the Peach Payments API, not "paymentType" or other variations.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-26T08:08:52.624Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 193
File: backend/connector-integration/src/connectors/rapyd/transformers.rs:505-524
Timestamp: 2025-09-26T08:08:52.624Z
Learning: In Rapyd connector (backend/connector-integration/src/connectors/rapyd/transformers.rs), the next_action field in ResponseData struct is required (not Optional) as per Rapyd API documentation. This field always appears in payment responses with values like "3d_verification", "pending_capture", "pending_confirmation", or "not_applicable", consistent with hyperswitch connector patterns.

Applied to files:

  • backend/connector-integration/src/connectors/archipel/transformers.rs
🧬 Code graph analysis (2)
backend/connector-integration/src/connectors/archipel.rs (3)
backend/connector-integration/src/connectors/macros.rs (2)
  • router_data (94-105)
  • request_body (66-75)
backend/interfaces/src/connector_integration_v2.rs (4)
  • get_error_response_v2 (136-145)
  • get_headers (51-56)
  • get_url (69-76)
  • get_ca_certificate (213-221)
backend/connector-integration/src/connectors/archipel/transformers.rs (17)
  • try_from (49-56)
  • try_from (67-70)
  • try_from (297-330)
  • try_from (400-433)
  • try_from (631-642)
  • try_from (655-696)
  • try_from (708-806)
  • try_from (830-886)
  • try_from (911-973)
  • try_from (981-1028)
  • try_from (1067-1086)
  • try_from (1099-1140)
  • try_from (1256-1272)
  • try_from (1285-1306)
  • try_from (1332-1355)
  • try_from (1402-1495)
  • serde_json (520-520)
backend/connector-integration/src/connectors/archipel/transformers.rs (2)
backend/connector-integration/src/connectors/macros.rs (1)
  • router_data (94-105)
backend/domain_types/src/connector_types.rs (3)
  • from (2216-2412)
  • to_connector_meta (681-688)
  • std (686-686)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)

}
}

fn to_connector_meta(
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can be an util function, also check whether similar util function exists or not.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/connector-integration/src/connectors/archipel.rs (1)

680-697: Remove leftover println! from authorize URL builder.

The println!("here"); in the Authorize get_url is a stray debug statement and will spam stdout in production. Please remove it or replace it with a proper tracing::debug! call if you really need this signal.

🧹 Nitpick comments (5)
backend/external-services/src/service.rs (1)

734-815: Previous critical mutual TLS issue has been resolved.

The rewritten match-based implementation now correctly handles mutual TLS by creating a reqwest::Identity from the client certificate and key, then building a client with that identity installed (lines 747-753). This addresses the previous critical regression where the client identity was never loaded.

The four-case structure is clear and handles the TLS configuration matrix appropriately:

  • Mutual TLS with optional CA verification
  • One-way TLS with CA verification only
  • Invalid partial configuration
  • Default no-certificate client

However, consider the following improvements:

1. Line ending normalization is incomplete (lines 740-741, 758, 782)

The .replace("\\r\\n", "\n") only handles escaped newlines (literal backslash-r-backslash-n sequences, as might appear in JSON). If the PEM string contains actual CRLF line endings (\r\n), they won't be normalized. Depending on how certificates are sourced, this could cause parsing failures.

Consider handling both escaped and actual line endings:

-let cert_pem = client_cert.expose().replace("\\r\\n", "\n");
-let key_pem = client_key.expose().replace("\\r\\n", "\n");
+let cert_pem = client_cert.expose()
+    .replace("\\r\\n", "\n")  // Handle escaped newlines
+    .replace("\r\n", "\n");    // Handle actual CRLF
+let key_pem = client_key.expose()
+    .replace("\\r\\n", "\n")
+    .replace("\r\n", "\n");

Apply similar changes to lines 758 and 782.

2. Invalid configuration silently falls back to base client (lines 804-807)

When only one of cert or key is provided, the code logs a warning and falls back to get_base_client. This silent degradation might mask configuration errors. Consider whether this should return an error instead, forcing the caller to provide valid configuration.

If you want to enforce strict validation:

 (Some(_), None, _) | (None, Some(_), _) => {
-    tracing::warn!("Incomplete client certificate configuration: both cert and key are required for mutual TLS");
-    get_base_client(proxy_config, should_bypass_proxy)
+    tracing::error!("Incomplete client certificate configuration: both cert and key are required for mutual TLS");
+    Err(report!(ApiClientError::InvalidProxyConfiguration))
+        .attach_printable("Mutual TLS requires both client certificate and private key")
 }

3. Document why rustls is required (lines 753, 789)

The mutual TLS and one-way TLS paths explicitly call .use_rustls_tls(), but the default base client does not. Consider adding a comment explaining why rustls is required for custom certificate handling (e.g., better PEM support, consistent behavior across platforms).

backend/connector-integration/src/connectors/archipel.rs (1)

733-749: Fix PSync error message string to reference the correct flow.

The attached printable message uses "connector_meta is required for Archipel capture flow" inside the PSync get_url path, which is misleading when debugging PSync issues. Consider updating the string to say "PSync flow" (or similar) to match the actual context.

backend/connector-integration/src/connectors/archipel/transformers.rs (3)

739-793: Use logical || instead of bitwise | for boolean combinations.

is_saved_card_payment and stored_on_file use | on booleans. This works, but || is the idiomatic operator and signals intent more clearly, especially to future readers.

Example:

-        let is_saved_card_payment = (router_data.request.is_mandate_payment())
-            | (router_data.request.setup_future_usage == Some(FutureUsage::OnSession));
+        let is_saved_card_payment = router_data.request.is_mandate_payment()
+            || router_data.request.setup_future_usage == Some(FutureUsage::OnSession);

-        let stored_on_file =
-            is_saved_card_payment | router_data.request.is_customer_initiated_mandate_payment();
+        let stored_on_file =
+            is_saved_card_payment || router_data.request.is_customer_initiated_mandate_payment();

880-921: Factor out shared 3DS-from-metadata parsing to avoid duplication.

The logic that pulls authentication_data (CAVV, ECI, ds_trans_id, message_version, timestamp) from request.metadata to build Archipel3DS is duplicated here and again in the SetupMandate transformer. Extracting this into a small helper (e.g., fn three_ds_from_metadata(metadata: &Value) -> Option<Archipel3DS>) would reduce drift if the required fields or mapping change.

This is a maintainability improvement only; current behavior is consistent and forwards 3DS data instead of dropping it.


1190-1239: Validate error-to-attempt-status mapping against Archipel’s error codes.

get_error_attempt_status currently infers AttemptStatus from simple substring checks on error_code plus the HTTP status. That’s reasonable as a first pass, but it’s heuristic; you might want to double‑check against Archipel’s documented error codes to ensure:

  • Card declines are always mapped to Failure (or whatever is expected by upstream),
  • Auth failures are consistently mapped to AuthenticationFailed,
  • Rate‑limit / server issues (429, 5xx) being treated as Pending matches your retry strategy.

If the mapping is correct, consider adding a short comment referencing the spec section or an internal doc so it’s clear this logic is intentional.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4364e18 and 4af86c3.

📒 Files selected for processing (3)
  • backend/connector-integration/src/connectors/archipel.rs (1 hunks)
  • backend/connector-integration/src/connectors/archipel/transformers.rs (1 hunks)
  • backend/external-services/src/service.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-24T08:45:31.195Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments.rs:306-315
Timestamp: 2025-09-24T08:45:31.195Z
Learning: In Peachpayments connector (backend/connector-integration/src/connectors/peachpayments.rs), the connector_transaction_id field has different types across flows: PaymentVoidData uses String directly, while PaymentsCaptureData uses ResponseId enum that requires pattern matching or get_connector_transaction_id() method.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-15T06:56:22.535Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/connector-integration/src/connectors/trustpay.rs:747-762
Timestamp: 2025-09-15T06:56:22.535Z
Learning: In Trustpay connector (backend/connector-integration/src/connectors/trustpay.rs), the refund_connector_metadata field has different data formats in different contexts: RSync expects it to be already parsed as JSON Value (accessing directly with .get()), while other refund flows expect it to be a JSON string that needs serde_json::from_str() parsing. The extract_payment_method_from_refund_metadata helper is designed for the latter case and should not be used in RSync.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-15T04:33:18.323Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 172
File: backend/grpc-server/tests/trustpay_payment_flows_test.rs:1-4
Timestamp: 2025-09-15T04:33:18.323Z
Learning: In test files for the juspay/connector-service repository, broad Clippy suppressions (#![allow(clippy::expect_used)], #![allow(clippy::unwrap_used)], #![allow(clippy::panic)]) are used as an established coding convention, as confirmed by the maintainer.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
📚 Learning: 2025-09-24T10:18:33.115Z
Learnt from: Anurag-05-prog
Repo: juspay/connector-service PR: 188
File: backend/connector-integration/src/connectors/peachpayments/transformers.rs:50-56
Timestamp: 2025-09-24T10:18:33.115Z
Learning: In Peach Payments connector API (backend/connector-integration/src/connectors/peachpayments/transformers.rs), the authorize request struct uses the field "charge_method" as expected by the Peach Payments API, not "paymentType" or other variations.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
📚 Learning: 2025-09-26T08:08:52.624Z
Learnt from: Shubhodip900
Repo: juspay/connector-service PR: 193
File: backend/connector-integration/src/connectors/rapyd/transformers.rs:505-524
Timestamp: 2025-09-26T08:08:52.624Z
Learning: In Rapyd connector (backend/connector-integration/src/connectors/rapyd/transformers.rs), the next_action field in ResponseData struct is required (not Optional) as per Rapyd API documentation. This field always appears in payment responses with values like "3d_verification", "pending_capture", "pending_confirmation", or "not_applicable", consistent with hyperswitch connector patterns.

Applied to files:

  • backend/connector-integration/src/connectors/archipel.rs
  • backend/connector-integration/src/connectors/archipel/transformers.rs
🧬 Code graph analysis (2)
backend/connector-integration/src/connectors/archipel.rs (1)
backend/connector-integration/src/connectors/archipel/transformers.rs (18)
  • try_from (49-56)
  • try_from (67-70)
  • try_from (297-330)
  • try_from (400-433)
  • try_from (637-648)
  • try_from (661-702)
  • try_from (714-812)
  • try_from (836-933)
  • try_from (958-1020)
  • try_from (1028-1075)
  • try_from (1114-1133)
  • try_from (1146-1187)
  • try_from (1303-1319)
  • try_from (1332-1353)
  • try_from (1379-1402)
  • try_from (1449-1583)
  • serde_json (520-520)
  • from_response (516-534)
backend/connector-integration/src/connectors/archipel/transformers.rs (2)
backend/domain_types/src/types.rs (1)
  • RawCardNumber (796-796)
backend/common_utils/src/lib.rs (1)
  • date_as_yyyymmddthhmmssmmmz (120-127)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
backend/external-services/src/service.rs (2)

680-680: CA certificate parameter added correctly.

The ca_certificate parameter is now passed through from the request to create_client, enabling server certificate verification in mutual TLS and one-way TLS scenarios.


730-733: Function signature updated appropriately.

The addition of the ca_certificate parameter completes the TLS configuration surface, allowing callers to specify server CA certificates for verification in addition to client certificates for mutual TLS.

backend/connector-integration/src/connectors/archipel/transformers.rs (1)

1309-1319: Confirm connector metadata shape for refund tenant resolution.

ArchipelRefundRequest::try_from expects request.connector_metadata to contain Archipel config (via ArchipelConfigData::try_fromto_connector_meta), while other flows use metadata or nested "connector_meta_data" values. Please ensure that the producer for refund requests is indeed sending connector metadata in the expected format (either direct JSON string or object with "connector_meta_data"), otherwise tenant resolution will fail at runtime.

@seekshiva seekshiva linked an issue Dec 2, 2025 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

coderabbit-ai-review Trigger CodeRabbit review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nov 12 - ARCHIPEL connector

4 participants