Integrating Twilio SMS API with Spring Boot

Sending an SMS from a Spring Boot application is useful for login verification, appointment reminders, delivery updates and payment notifications. Twilio provides a REST API and Java SDK that make this integration straightforward, while Spring Boot handles configuration, dependency injection and HTTP endpoints cleanly.

For Australian businesses, SMS can reach customers in Sydney, Melbourne, Brisbane, Perth and regional areas without requiring a mobile app. It also suits everyday habits such as receiving parcel updates, confirming a tradie booking or approving a bank-style security code on an Australian mobile number.

The implementation should account for delivery status, international number formats and message consent. A reliable service should also protect Twilio credentials, avoid logging verification codes and handle provider errors without exposing internal details to users.

The following example uses Maven, Spring Boot and the Twilio Java helper library. The same design can be adapted for Spring Security authentication, a JDBC-backed notification queue or a Spring Data order system.

Set Up Twilio Credentials Safely

Create a Twilio account, obtain an Account SID and Auth Token, then provision a sender suitable for Australian traffic. Depending on the use case, this may be a Twilio phone number or an approved alphanumeric sender ID. Check current Twilio requirements for Australian destinations before moving to production.

Add the dependency to pom.xml:

<dependency>
    <groupId>com.twilio.sdk</groupId>
    <artifactId>twilio</artifactId>
    <version>10.6.6</version>
</dependency>

Keep credentials outside source control. Environment variables work well for a small deployment, while AWS Secrets Manager, Azure Key Vault or a Kubernetes secret is more appropriate for a production service.

twilio:
  account-sid: ${TWILIO_ACCOUNT_SID}
  auth-token: ${TWILIO_AUTH_TOKEN}
  from-number: ${TWILIO_FROM_NUMBER}

Create A Configurable SMS Client

Bind the Twilio settings with a configuration properties class. Initialising the SDK once during application startup avoids repeated setup for every request.

@ConfigurationProperties(prefix = "twilio")
public record TwilioProperties(
        String accountSid,
        String authToken,
        String fromNumber) {}

Enable configuration properties and create a service that sends messages through Twilio’s Message.creator API:

@Service
public class SmsService {
    private final TwilioProperties properties;

    public SmsService(TwilioProperties properties) {
        this.properties = properties;
        Twilio.init(properties.accountSid(), properties.authToken());
    }

    public String send(String recipient, String body) {
        Message message = Message.creator(
                new PhoneNumber(recipient),
                new PhoneNumber(properties.fromNumber()),
                body
        ).create();

        return message.getSid();
    }
}

The recipient should use E.164 format, such as +61412345678, rather than a local format like 0412 345 678. Normalise and validate numbers before calling the provider.

Expose A Safe Spring Boot Endpoint

A request object keeps the API contract explicit. In a real application, restrict this endpoint to an authenticated internal client rather than allowing an anonymous caller to send arbitrary messages.

public record SmsRequest(
        @NotBlank String phoneNumber,
        @NotBlank @Size(max = 320) String message) {}

A controller can validate the input and return the provider message ID:

@RestController
@RequestMapping("/api/messages")
public class SmsController {
    private final SmsService smsService;

    public SmsController(SmsService smsService) {
        this.smsService = smsService;
    }

    @PostMapping("/sms")
    public ResponseEntity<Map<String, String>> send(
            @Valid @RequestBody SmsRequest request) {
        String sid = smsService.send(
                request.phoneNumber(), request.message());
        return ResponseEntity.accepted()
                .body(Map.of("messageSid", sid));
    }
}

In production, add rate limiting, audit records and a global exception handler. Avoid returning the Twilio exception text directly because it may reveal account or provider details.

Validate Consent And Australian Requirements

Australian commercial SMS is regulated by the Spam Act 2003 and overseen by the Australian Communications and Media Authority. Marketing messages generally require consent, sender identification and a functional unsubscribe mechanism. Transactional messages still need careful handling, especially when promotional content is added.

The Privacy Act 1988 and the Australian Privacy Principles also matter when phone numbers and message history are stored. Keep retention periods limited, restrict staff access and document why a number is collected. A message containing a one-time password should never be written to ordinary application logs.

Useful safeguards for an Australian deployment include:

A customer in Brisbane, Adelaide or Perth may receive a scheduled message at a different local time from a customer in Melbourne. Daylight saving affects some states, so store timestamps in UTC and convert them using the customer’s known zone.

Handle Failures And Delivery Status

The API accepting a message does not guarantee that the handset received it. Twilio returns a message SID and can send status callbacks for queued, sent, delivered, failed or undelivered states. Save the SID alongside an order, booking or authentication event.

For temporary failures, a queue such as RabbitMQ, Kafka or a database-backed worker can retry delivery with a limit and back-off period. Permanent errors, invalid numbers and opt-outs should be marked clearly instead of retried indefinitely.

You can register a status callback when creating a message:

Message.creator(
        new PhoneNumber(recipient),
        new PhoneNumber(properties.fromNumber()),
        body
).setStatusCallback(
        URI.create("https://example.com/api/twilio/status")
).create();

Protect the callback endpoint by validating Twilio’s request signature. Also separate operational alerts from customer-facing errors, so a provider outage produces a useful support event rather than a stack trace in the browser.

Test The Integration Before Release

Use Twilio test credentials where appropriate and verify the complete path in a staging environment. Test Australian mobile numbers, invalid input, duplicate requests, provider failures and messages containing accented characters. GSM character limits can change when Unicode characters are used, potentially splitting one message into multiple segments.

A practical release checklist includes:

For higher volume, move sending out of the controller thread and use an outbox pattern. The application can first commit a notification record with the business transaction, then a worker can call Twilio, record the SID and retry safely. This approach prevents an SMS provider timeout from rolling back an important order or booking.