Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,83 @@ public static void main(String[] args) {
}
```

### Bacs Direct Debit

Send a pre-notification (advance notice) to a payer before collecting funds from their account. The
endpoint accepts the secret key only, so it is not available on an OAuth-only client.

```java
import com.checkout.CheckoutApi;
import com.checkout.apm.bacs.BacsNotificationRequest;
import com.checkout.apm.bacs.BacsNotificationResponse;
import com.checkout.apm.bacs.BacsNotificationType;
import com.checkout.common.Currency;

import java.time.LocalDate;

final BacsNotificationRequest request = BacsNotificationRequest.builder()
.sourceId("src_wmlfc3zyhqzehihu7giusaaawu")
.notificationType(BacsNotificationType.ADVANCE_NOTICE)
.collectionDate(LocalDate.of(2026, 7, 15))
.amount(4999L)
.currency(Currency.GBP)
.reference("INV-12345") // optional
.customerEmail("customer@example.com")
.billingDescriptor("CHECKOUT")
.supportEmail("support@test.com")
.supportPhone("+447700900123") // optional
.build();

final CompletableFuture<BacsNotificationResponse> notification =
checkoutApi.bacsClient().sendNotification(request);
```

A Bacs Direct Debit instrument is stored, updated and retrieved through the instruments client. Note
that the Bacs `payment_type` values are capitalized (`Recurring`, `Regular`), unlike the SEPA ones,
so use `BacsPaymentType` and not `SepaPaymentType`:

```java
import com.checkout.common.CountryCode;
import com.checkout.common.Currency;
import com.checkout.instruments.BacsPaymentType;
import com.checkout.instruments.create.CreateBacsAccountHolder;
import com.checkout.instruments.create.CreateBacsBillingAddress;
import com.checkout.instruments.create.CreateBacsInstrumentAccount;
import com.checkout.instruments.create.CreateBacsInstrumentData;
import com.checkout.instruments.create.CreateInstrumentBacsRequest;
import com.checkout.instruments.create.CreateInstrumentBacsResponse;
import com.checkout.instruments.get.GetBacsInstrumentResponse;

final CreateInstrumentBacsRequest request = CreateInstrumentBacsRequest.builder()
.account(CreateBacsInstrumentAccount.builder()
.processingChannelId("pc_q4dbxom5jbgudnjzjpz7j2z6uq")
.build())
.instrumentData(CreateBacsInstrumentData.builder()
.accountNumber("86753246") // 8 characters
.bankCode("040004") // the sort code, 6 characters
.country(CountryCode.GB)
.currency(Currency.GBP)
.paymentType(BacsPaymentType.RECURRING)
.build())
.accountHolder(CreateBacsAccountHolder.builder()
.firstName("John")
.lastName("Smith")
.billingAddress(CreateBacsBillingAddress.builder()
.country(CountryCode.GB)
.build())
.build())
.build();

final CreateInstrumentBacsResponse created =
checkoutApi.instrumentsClient().<CreateInstrumentBacsResponse>create(request).get();

final GetBacsInstrumentResponse stored =
(GetBacsInstrumentResponse) checkoutApi.instrumentsClient().get(created.getId()).get();
```

To take a payment against a stored Bacs instrument, use `RequestBacsSource`. The payment response
returns a `BacsResponseSource`.

## Logging

The SDK supports SLF4J as logger provider, you need to provide your configuration file through `resources` folder.
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/checkout/AbstractCheckoutApmApi.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.checkout;

import com.checkout.apm.bacs.BacsClient;
import com.checkout.apm.bacs.BacsClientImpl;
import com.checkout.apm.ideal.IdealClient;
import com.checkout.apm.ideal.IdealClientImpl;
import com.checkout.apm.previous.klarna.KlarnaClient;
Expand All @@ -14,12 +16,14 @@ public abstract class AbstractCheckoutApmApi {
protected final ApiClient apiClient;

private final IdealClient idealClient;
private final BacsClient bacsClient;
private final KlarnaClient klarnaClient;
private final SepaClient sepaClient;

protected AbstractCheckoutApmApi(final CheckoutConfiguration configuration) {
this.apiClient = getBaseApiClient(configuration);
this.idealClient = new IdealClientImpl(apiClient, configuration);
this.bacsClient = new BacsClientImpl(apiClient, configuration);
this.klarnaClient = new KlarnaClientImpl(apiClient, configuration);
this.sepaClient = new SepaClientImpl(apiClient, configuration);
}
Expand All @@ -28,6 +32,10 @@ public IdealClient idealClient() {
return idealClient;
}

public BacsClient bacsClient() {
return bacsClient;
}

public KlarnaClient klarnaClient() {
return klarnaClient;
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/checkout/CheckoutApmApi.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package com.checkout;

import com.checkout.apm.bacs.BacsClient;
import com.checkout.apm.ideal.IdealClient;

/**
* The alternative payment method clients that the current platform exposes.
*/
public interface CheckoutApmApi {

/**
* Retrieves iDEAL issuer information.
*
* @return the iDEAL client.
*/
IdealClient idealClient();

/**
* Sends Bacs Direct Debit pre-notifications.
*
* @return the Bacs Direct Debit client.
*/
BacsClient bacsClient();

}
46 changes: 28 additions & 18 deletions src/main/java/com/checkout/GsonSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,13 @@ public final class GsonSerializer implements Serializer {
.registerTypeAdapterFactory(
RuntimeTypeAdapterFactory.of(
com.checkout.handlepaymentsandpayouts.payments.common.source.AbstractSource.class,
CheckoutUtils.TYPE
CheckoutUtils.TYPE,
true
)
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.cardsource.CardSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.CARD))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.achsource.AchSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.ACH))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.bacssource.BacsSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.BACS))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.bankaccountsource.BankAccountSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.BANK_ACCOUNT))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.afterpaysource.AfterpaySource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.AFTERPAY))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.alipaycnsource.AlipayCnSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.ALIPAY_CN))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.alipayhksource.AlipayHkSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.ALIPAY_HK))
Expand Down Expand Up @@ -152,10 +156,10 @@ public final class GsonSerializer implements Serializer {
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.twintsource.TwintSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.TWINT))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.vippssource.VippsSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.VIPPS))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.wechatpaysource.WechatpaySource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.WECHATPAY))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponsegiropaysourcesource.PaymentGetResponseGiropaySourceSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_GIROPAY_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponseklarnasourcesource.PaymentGetResponseKlarnaSourceSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_KLARNA_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponsesepavfoursourcesource.PaymentGetResponseSEPAVFourSourceSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_SEPAV4_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentresponsesourcesource.PaymentResponseSourceSource.class, identifier(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_RESPONSE_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponsegiropaysourcesource.PaymentGetResponseGiropaySourceSource.class, serializedName(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_GIROPAY_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponseklarnasourcesource.PaymentGetResponseKlarnaSourceSource.class, serializedName(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_KLARNA_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentgetresponsesepavfoursourcesource.PaymentGetResponseSEPAVFourSourceSource.class, serializedName(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_GET_RESPONSE_SEPAV4_SOURCE))
.registerSubtype(com.checkout.handlepaymentsandpayouts.payments.common.source.paymentresponsesourcesource.PaymentResponseSourceSource.class, serializedName(com.checkout.handlepaymentsandpayouts.payments.common.source.SourceType.PAYMENT_RESPONSE_SOURCE))
)
// Payments PREVIOUS - source
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.payments.previous.response.source.ResponseSource.class, CheckoutUtils.TYPE, true, com.checkout.payments.previous.response.source.AlternativePaymentSourceResponse.class)
Expand All @@ -167,7 +171,8 @@ public final class GsonSerializer implements Serializer {
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.payments.response.source.ResponseSource.class, CheckoutUtils.TYPE, true, com.checkout.payments.response.source.AlternativePaymentSourceResponse.class)
.registerSubtype(com.checkout.payments.response.source.CardResponseSource.class, identifier(PaymentSourceType.CARD))
.registerSubtype(com.checkout.payments.response.source.CurrencyAccountResponseSource.class, identifier(PaymentSourceType.CURRENCY_ACCOUNT))
.registerSubtype(com.checkout.payments.response.source.PayPalResponseSource.class, identifier(PaymentSourceType.PAYPAL)))
.registerSubtype(com.checkout.payments.response.source.PayPalResponseSource.class, identifier(PaymentSourceType.PAYPAL))
.registerSubtype(com.checkout.payments.response.source.BacsResponseSource.class, identifier(PaymentSourceType.BACS)))
// Payment Contexts
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.payments.response.source.contexts.ResponseSource.class, CheckoutUtils.TYPE, true, com.checkout.payments.response.source.contexts.AlternativePaymentSourceResponse.class)
.registerSubtype(com.checkout.payments.response.source.contexts.PaymentContextsPayPalResponseSource.class, identifier(PaymentSourceType.PAYPAL))
Expand All @@ -183,42 +188,47 @@ public final class GsonSerializer implements Serializer {
.registerSubtype(com.checkout.payments.sender.PaymentIndividualSender.class, identifier(SenderType.INDIVIDUAL))
.registerSubtype(com.checkout.payments.sender.PaymentInstrumentSender.class, identifier(SenderType.INSTRUMENT)))
// Instruments CS2
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.create.CreateInstrumentResponse.class, CheckoutUtils.TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.create.CreateInstrumentResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(com.checkout.instruments.create.CreateInstrumentBankAccountResponse.class, identifier(InstrumentType.BANK_ACCOUNT))
.registerSubtype(com.checkout.instruments.create.CreateInstrumentTokenResponse.class, identifier(InstrumentType.CARD))
.registerSubtype(com.checkout.instruments.create.CreateInstrumentSepaResponse.class, identifier(InstrumentType.SEPA)))
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.get.GetInstrumentResponse.class, CheckoutUtils.TYPE)
.registerSubtype(com.checkout.instruments.create.CreateInstrumentSepaResponse.class, identifier(InstrumentType.SEPA))
.registerSubtype(com.checkout.instruments.create.CreateInstrumentBacsResponse.class, identifier(InstrumentType.BACS))
.registerSubtype(com.checkout.instruments.create.CreateInstrumentAchResponse.class, identifier(InstrumentType.ACH)))
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.get.GetInstrumentResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(com.checkout.instruments.get.GetBankAccountInstrumentResponse.class, identifier(InstrumentType.BANK_ACCOUNT))
.registerSubtype(com.checkout.instruments.get.GetCardInstrumentResponse.class, identifier(InstrumentType.CARD))
.registerSubtype(com.checkout.instruments.get.GetSepaInstrumentResponse.class, identifier(InstrumentType.SEPA)))
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.update.UpdateInstrumentResponse.class, CheckoutUtils.TYPE)
.registerSubtype(com.checkout.instruments.get.GetSepaInstrumentResponse.class, identifier(InstrumentType.SEPA))
.registerSubtype(com.checkout.instruments.get.GetBacsInstrumentResponse.class, identifier(InstrumentType.BACS))
.registerSubtype(com.checkout.instruments.get.GetAchInstrumentResponse.class, identifier(InstrumentType.ACH)))
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.instruments.update.UpdateInstrumentResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentBankAccountResponse.class, identifier(InstrumentType.BANK_ACCOUNT))
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentCardResponse.class, identifier(InstrumentType.CARD))
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentSepaResponse.class, identifier(InstrumentType.SEPA))
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentAchResponse.class, identifier(InstrumentType.ACH)))
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentAchResponse.class, identifier(InstrumentType.ACH))
.registerSubtype(com.checkout.instruments.update.UpdateInstrumentBacsResponse.class, identifier(InstrumentType.BACS)))
// Workflows CS2
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.workflows.actions.response.WorkflowActionResponse.class, CheckoutUtils.TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.workflows.actions.response.WorkflowActionResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(com.checkout.workflows.actions.response.WebhookWorkflowActionResponse.class, identifier(WorkflowActionType.WEBHOOK)))
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.workflows.conditions.response.WorkflowConditionResponse.class, CheckoutUtils.TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.workflows.conditions.response.WorkflowConditionResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(com.checkout.workflows.conditions.response.EventWorkflowConditionResponse.class, identifier(WorkflowConditionType.EVENT))
.registerSubtype(com.checkout.workflows.conditions.response.EntityWorkflowConditionResponse.class, identifier(WorkflowConditionType.ENTITY))
.registerSubtype(com.checkout.workflows.conditions.response.ProcessingChannelWorkflowConditionResponse.class, identifier(WorkflowConditionType.PROCESSING_CHANNEL)))
// Accounts CS2 - PayoutSchedules
.registerTypeAdapter(GetScheduleResponse.class, getScheduleResponseDeserializer())
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.accounts.payout.schedule.response.ScheduleResponse.class, CheckoutUtils.FREQUENCY)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.accounts.payout.schedule.response.ScheduleResponse.class, CheckoutUtils.FREQUENCY, true)
.registerSubtype(com.checkout.accounts.payout.schedule.response.ScheduleFrequencyDailyResponse.class, CheckoutUtils.DAILY)
.registerSubtype(com.checkout.accounts.payout.schedule.response.ScheduleFrequencyWeeklyResponse.class, CheckoutUtils.WEEKLY)
.registerSubtype(ScheduleFrequencyMonthlyResponse.class, CheckoutUtils.MONTHLY))
// Issuing CS2 - CardDetailsResponse
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(CardDetailsResponse.class, CheckoutUtils.TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(CardDetailsResponse.class, CheckoutUtils.TYPE, true)
.registerSubtype(PhysicalCardDetailsResponse.class, identifier(CardType.PHYSICAL))
.registerSubtype(VirtualCardDetailsResponse.class, identifier(CardType.VIRTUAL)))
// Issuing CS2 - CardControlsResponse
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(CardControlResponse.class, CheckoutUtils.CONTROL_TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(CardControlResponse.class, CheckoutUtils.CONTROL_TYPE, true)
.registerSubtype(VelocityCardControlResponse.class, identifier(ControlType.VELOCITY_LIMIT))
.registerSubtype(MccCardControlResponse.class, identifier(ControlType.MCC_LIMIT)))
// Issuing CS2 - ControlGroupControl
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.issuing.controls.requests.controlgroup.ControlGroupControl.class, CheckoutUtils.CONTROL_TYPE)
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(com.checkout.issuing.controls.requests.controlgroup.ControlGroupControl.class, CheckoutUtils.CONTROL_TYPE, true)
.registerSubtype(com.checkout.issuing.controls.requests.controlgroup.VelocityControlGroupControl.class, identifier(ControlType.VELOCITY_LIMIT))
.registerSubtype(com.checkout.issuing.controls.requests.controlgroup.MccControlGroupControl.class, identifier(ControlType.MCC_LIMIT))
.registerSubtype(com.checkout.issuing.controls.requests.controlgroup.MidControlGroupControl.class, identifier(ControlType.MID_LIMIT)))
Expand Down
Loading
Loading