This example demonstrates a payment form using the Multibanco payment method, a popular bank payment network in Portugal. After initiating the charge, the customer receives an entity number and reference number to complete the payment at an ATM or online banking portal.
You can optionally set an expiry deadline for the payment by passing multibanco.expiresAt when creating the charge.
This field accepts a Unix timestamp (seconds since epoch) representing the moment the payment deadline expires.
It must be at least 1 minute and at most 7 days in the future.
In test mode, the expiry is capped at 15 minutes regardless of the value provided.
Once the deadline passes, the charge is automatically failed.
If no expiresAt is provided, a default expiry of 7 days is applied automatically.
This example sets expiresAt based on the billing name you provide.
Use the following naming convention to trigger a specific expiry duration:
Any other billing name defaults to a 60-minute expiry. In test mode the backend caps the simulator delay at 15 minutes, so a charge with a longer expiry auto-fails after 15 minutes.
The full transaction involves a few straightforward steps:
pending status and flow.nextAction equals redirect.successful or failed depending on the payment outcome.
Every Charge includes a clientObjectId, which can be used with shift4.js. It allows retrieving all necessary payment information in the browser without exposing sensitive data.
By using shift4.js, handling the Multibanco flow becomes easier. It can manage redirects and automatically track the final payment status for you.
To use this functionality, pass the clientObjectId from your server to the browser and invoke the handleChargeNextAction method with it.
You'll need to access clientObjectId in two situations:
Once the payment is completed, handleChargeNextAction will resolve with a minimal Charge object, exposing only the required result information, ensuring user privacy and security.
@RestController
@RequestMapping("/ajax/examples/charge-with-multibanco")
@RequiredArgsConstructor
class ExamplesAjaxChargeWithMultibancoController {
@PostMapping("/payment")
Map<String, String> ajaxPaymentMethod(@RequestBody PaymentMethodExampleRequest exampleRequest) throws IOException {
try (Shift4Gateway shift4Gateway = createShift4GatewayForPaymentMethods()) {
long expiresAt = Instant.now().plusSeconds(60 * 60L).getEpochSecond(); // 1 hour from now
var paymentMethodRequest = new PaymentMethodRequest()
.set("type", "multibanco")
.set("multibanco", Map.of("expiresAt", expiresAt))
.billing(new BillingRequest()
.name(exampleRequest.name)
.address(new AddressRequest().country("PT")));
var paymentMethod = shift4Gateway.createPaymentMethod(paymentMethodRequest);
var chargeRequest = new ChargeRequest(100, "EUR")
.paymentMethod(new PaymentMethodRequest(paymentMethod.getId()))
.flow(new ChargeFlowRequest()
.returnUrl("https://your-website.com/examples/charge-with-multibanco"));
var charge = shift4Gateway.createCharge(chargeRequest);
return singletonMap("clientObjectId", charge.getClientObjectId());
} catch (Shift4Exception e) {
throw new BadRequestException(e.getMessage());
}
}
private static int resolveExpiryMinutes(String billingName) {
if (billingName != null) {
Matcher matcher = Pattern.compile("(?i)expire after (\\d+)").matcher(billingName);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
}
return 60;
}
static class PaymentMethodExampleRequest {
String name;
}
}