Here you'll find documentation related to the Sinch Java SDK, including how to install it, initialize it, and start developing Java code using Sinch services.
To use Sinch services, you'll need a Sinch account and access keys. You can sign up for an account and create access keys at dashboard.sinch.com.
For more information on the SDK, refer to the dedicated Java SDK documentation section and the Javadoc. For the Sinch APIs on which this SDK is based, refer to the official developer documentation portal.
- Prerequisites
- Installation
- Supported APIs
- Getting started
- Logging
- Handling Exceptions
- Third-party dependencies
- Examples
- Changelog and Migration
- License
- Contact
Warning: This SDK is intended for server-side (backend) use only. Do not use it in front-end or client-side applications (web, mobile, or desktop), regardless of language or framework. Doing so can expose your Sinch credentials to end-users.
Add the SDK dependency to your pom.xml file:
<dependencies>
<dependency>
<groupId>com.sinch.sdk</groupId>
<artifactId>sinch-sdk-java</artifactId>
<version>${sdk.version}</version>
</dependency>
...
</dependencies>Note: The ${sdk.version} needs to be set according to the released version to be used (see available versions from Maven Repository)
| API Category | API Name |
|---|---|
| Messaging | Conversation API |
| SMS API | |
| Voice and Video | Voice API |
| Numbers | Numbers API |
| Verification | Verification API |
Note: The SMS API is end-of-sale. New integrations should use the Conversation API instead, which supports SMS and many other channels.
To start using the SDK, initialize the main client class. This client gives you access to all the SDK services:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
// Warning: not all APIs support project authentication. Check the section for each API before using this snippet.
Configuration configuration =
Configuration.builder()
.setProjectId(PROJECT_ID)
.setKeyId(KEY_ID)
.setKeySecret(KEY_SECRET)
.build();
SinchClient client = new SinchClient(configuration);Get projectId, keyId and keySecret from the Access keys page in your Sinch dashboard (keySecret is shown only once, at creation time). It's highly recommended to not hardcode these credentials: load them from environment variables for local development, and from a secret manager in production.
This snippet is the common starting point for project-based API. Some APIs need a different initialization or extra parameters (for example, a region or application credentials), see the section for each API below.
The Conversation API is regionalized. To use this API, the conversationRegion parameter is required:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.ConversationRegion;
Configuration configuration =
Configuration.builder()
.setProjectId(PROJECT_ID)
.setKeyId(KEY_ID)
.setKeySecret(KEY_SECRET)
.setConversationRegion(ConversationRegion.EU)
.build();
SinchClient client = new SinchClient(configuration);The Conversation API delivers asynchronous Sinch Events to the Event Destination URL you configure for your app in the Conversation dashboard. validateAuthenticationHeader confirms a request comes from Sinch and parseEvent turns its payload into an event object. headers and body are the incoming request's headers and raw body:
import com.sinch.sdk.domains.conversation.api.v1.SinchEventsService;
import com.sinch.sdk.domains.conversation.models.v1.sinchevents.ConversationSinchEvent;
SinchEventsService sinchEvents = sinchClient.conversation().v1().sinchEvents();
boolean validAuth = sinchEvents.validateAuthenticationHeader(sinchEventsSecret, headers, body);
ConversationSinchEvent event = sinchEvents.parseEvent(body);sinchEventsSecret is set per app in the Conversation dashboard. parseEvent works without validating the request, but then its origin can't be verified, so validating is recommended in production.
You can find a complete example in examples/sinch-events.
Warning: the SMS API is end-of-sale. For new integrations, prefer the Conversation API.
The SMS API is regionalized: set smsRegion to the region where your SMS account is hosted. The accepted values are US, EU, AU, BR and CA, and the region also determines which credentials you can use:
- Project access keys — available only in the
USandEUregions. Use the sameprojectId,keyIdandkeySecretas the common client, plussmsRegion:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.SMSRegion;
Configuration configuration =
Configuration.builder()
.setProjectId(PROJECT_ID)
.setKeyId(KEY_ID)
.setKeySecret(KEY_SECRET)
.setSmsRegion(SMSRegion.US)
.build();
SinchClient client = new SinchClient(configuration);SMS authentication for new projects
Projects created after the SMS API end-of-sale (
15/04/26) cannot use project access keys — the SMS API requests return401 Unauthorized.If you encounter this issue, consider the following options:
- Use service plan credentials (
smsServicePlanId+smsApiToken)- Use the Conversation API, which works with project access keys.
- Contact your account manager
- Service plan — available in all regions (
US,EU,AU,BR,CA). Use asmsServicePlanIdandsmsApiToken, both available on the Service APIs dashboard:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.SMSRegion;
Configuration configuration =
Configuration.builder()
.setSmsServicePlanId(SERVICE_PLAN_ID)
.setSmsApiToken(API_TOKEN)
.setSmsRegion(SMSRegion.US)
.build();
SinchClient client = new SinchClient(configuration);The SMS API delivers asynchronous Sinch Events to an Event Destination, whose URL is set per batch with the eventDestinationTarget parameter on the send, update and replace operations. validateAuthenticationHeader confirms a request comes from Sinch and parseEvent turns its payload into an event object. headers and body are the incoming request's headers and raw body:
import com.sinch.sdk.domains.sms.api.v1.SinchEventsService;
import com.sinch.sdk.domains.sms.models.v1.sinchevents.SmsSinchEvent;
SinchEventsService sinchEvents = client.sms().v1().sinchEvents();
boolean validAuth = sinchEvents.validateAuthenticationHeader(sinchEventsSecret, headers, body);
SmsSinchEvent event = sinchEvents.parseEvent(body);Signature authentication for SMS events must be enabled for your account by your account manager. Until it is activated, signature headers will not be present and parseEvent can be called directly without signature validation. See the SMS events documentation.
You can find a complete example in examples/sinch-events.
The Numbers API needs no extra parameters, use the common client shown above.
The Numbers API delivers asynchronous Sinch Events to the Event Destination URL you configure for your project through sinchClient.numbers().v1().eventDestinations(). validateAuthenticationHeader confirms a request comes from Sinch and parseEvent turns its payload into an event object. headers and body are the incoming request's headers and raw body:
import com.sinch.sdk.domains.numbers.api.v1.SinchEventsService;
import com.sinch.sdk.domains.numbers.models.v1.sinchevents.NumberSinchEvent;
SinchEventsService sinchEvents = client.numbers().v1().sinchEvents();
boolean validAuth = sinchEvents.validateAuthenticationHeader(sinchEventsSecret, headers, body);
NumberSinchEvent event = sinchEvents.parseEvent(body);sinchEventsSecret is the HmacSecret value configured on the Event Destination. parseEvent works without validating the request, but then its origin can't be verified, so validating is recommended in production.
You can find a complete example in examples/sinch-events.
The Verification API uses application credentials. Set applicationKey and applicationSecret, both available on the Apps dashboard:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
Configuration configuration =
Configuration.builder()
.setApplicationKey(APPLICATION_KEY)
.setApplicationSecret(APPLICATION_SECRET)
.build();
SinchClient client = new SinchClient(configuration);The Verification API delivers synchronous Sinch Events to the Event Destination URL configured for your app. Requests are signed with your application credentials, so validation requires the HTTP verb and URI of the controller handling the request, in addition to the headers and raw body:
import com.sinch.sdk.domains.verification.api.v1.SinchEventsService;
SinchEventsService sinchEvents = client.verification().v1().sinchEvents();
boolean validAuth = sinchEvents.validateAuthenticationHeader("POST", "/VerificationEvent", headers, body);
var event = sinchEvents.parseEvent(body);Some events expect a response: build it from the business layer and serialize it with sinchEvents.serializeResponse(response) before returning it to Sinch.
You can find a complete example in examples/sinch-events.
The Voice API uses application credentials. Set applicationKey and applicationSecret (both available on the Apps dashboard); voiceRegion is optional and defaults to a global region:
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.VoiceRegion;
Configuration configuration =
Configuration.builder()
.setApplicationKey(APPLICATION_KEY)
.setApplicationSecret(APPLICATION_SECRET)
.setVoiceRegion(VoiceRegion.GLOBAL)
.build();
SinchClient client = new SinchClient(configuration);The Voice API delivers synchronous Sinch Events to the Event Destination URL configured for your app. Requests are signed with your application credentials, so validation requires the HTTP verb and URI of the controller handling the request, in addition to the headers and raw body:
import com.sinch.sdk.domains.voice.api.v1.SinchEventsService;
SinchEventsService sinchEvents = client.voice().v1().sinchEvents();
boolean validAuth = sinchEvents.validateAuthenticationHeader("POST", "/VoiceEvent", headers, body);
var event = sinchEvents.parseEvent(body);Some events (for example an incoming call) expect a SVAML response: build it from the business layer and serialize it with sinchEvents.serializeResponse(response) before returning it to Sinch.
You can find a complete example in examples/sinch-events.
Once your client is configured, you can send your first message. The example below uses the Conversation API to send a simple text message over SMS. Replace CONVERSATION_APP_ID with your app ID, SINCH_VIRTUAL_PHONE_NUMBER with your Sinch number and RECIPIENT_PHONE_NUMBER with the recipient's phone number:
import com.sinch.sdk.domains.conversation.models.v1.ChannelRecipientIdentities;
import com.sinch.sdk.domains.conversation.models.v1.ChannelRecipientIdentity;
import com.sinch.sdk.domains.conversation.models.v1.ConversationChannel;
import com.sinch.sdk.domains.conversation.models.v1.messages.AppMessage;
import com.sinch.sdk.domains.conversation.models.v1.messages.request.SendMessageRequest;
import com.sinch.sdk.domains.conversation.models.v1.messages.response.SendMessageResponse;
import com.sinch.sdk.domains.conversation.models.v1.messages.types.text.TextMessage;
import java.util.Collections;
SendMessageRequest<TextMessage> request =
SendMessageRequest.<TextMessage>builder()
.setAppId("CONVERSATION_APP_ID")
.setRecipient(
ChannelRecipientIdentities.of(
ChannelRecipientIdentity.builder()
.setChannel(ConversationChannel.SMS)
.setIdentity("RECIPIENT_PHONE_NUMBER")
.build()))
.setMessage(
AppMessage.<TextMessage>builder()
.setBody(TextMessage.builder().setText("Hello from the Sinch Java SDK!").build())
.build())
.setChannelProperties(Collections.singletonMap("SMS_SENDER", "SINCH_VIRTUAL_PHONE_NUMBER"))
.build();
SendMessageResponse response = client.conversation().messages().sendMessage(request);The SDK uses the Java 8 logging feature (java.util.logging)
When using Java logging, Loggers and severity can be configured by using a logging.properties file like:
# java.util.logging configuration sample
# See https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html#package.description
#
# Layers logging severity configuration
#
# Sinch SDK
com.sinch.level = INFO
# Apache HTTP Client
# org.apache.hc.level =
#
# console output handler sample
#
handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%4$-7s %2$s] %5$s %n
java.util.logging.ConsoleHandler.level = FINEST
If you are using a different logging framework (such as SLF4J or Spring), please refer to the documentation for your specific framework.
When a backend call is unsuccessful, the SDK throws an ApiException (from com.sinch.sdk.core.exceptions). It is the base class for all Sinch API exceptions and exposes the HTTP status code through getCode().
import com.sinch.sdk.core.exceptions.ApiException;
import com.sinch.sdk.domains.numbers.api.v1.NumbersService;
NumbersService numbersService = sinchClient.numbers().v1();
try {
AvailableNumbersListResponse response =
numbersService.searchForAvailableNumbers(
AvailableNumbersListQueryParameters.builder()
.setRegionCode("US")
.setType(NumberType.LOCAL)
.build());
} catch (ApiException e) {
// e.getCode() holds the HTTP status code, e.getMessage() the error detail
}ApiException is an unchecked exception, so wrapping calls in a try/catch is optional but recommended. Catching ApiException handles every error raised by an API call, including its more specific subclasses:
ApiAuthException: authentication/authorization failures.ApiMappingException: the response payload could not be deserialized into the expected type.
The SDK relies on the following third-party dependencies:
- Jackson: provides JSON serialization/deserialization functionality.
- Apache HTTP client: manages communication with Sinch products' REST APIs.
The transition from javax to jakarta namespaces with the Java EE to Jakarta EE migration may cause compatibility issues. Refer to Oracle's note about the transition for additional details.
Jackson maintainers provide two variants of the library:
(*) NOTE: Jakarta-RS is the package under jakarta.ws.rs, replacing older JAX-RS which lived under javax.ws.rs. For JAX-RS variant, see repo jackson-jaxrs-providers
By default, the Sinch Java SDK uses the "new" jackson-jakarta-rs-providers. However, you can switch to the "older" jackson-jaxrs-providers if required.
Depending on your use case, you may need to adjust dependencies to enable jaxrs usage.
Add the following dependency to your configuration:
Note: Replace VERSION-YOU-WANT-TO-BE-USED with a Jackson version of at least 2.15.2.
...
<dependency>
<groupId>com.sinch.sdk</groupId>
<artifactId>sinch-sdk-java</artifactId>
<version>${sinch.sdk.java.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>VERSION-YOU-WANT-TO-BE-USED</version>
</dependency>
...You can find:
- self-contained code snippets covering every API operation in the examples/snippets folder.
- getting started guides for specific use cases in the examples/getting-started folder.
- a Spring Boot server template to process received Sinch Events in the examples/sinch-events folder.
- an SDK client template application in the examples/client folder.
- step-by-step tutorials combining multiple SDK features in the examples/tutorials folder.
For information about the latest changes in the SDK, please refer to the CHANGELOG file and the MIGRATION-GUIDE for instructions on how to update your code when upgrading to a new major version of the SDK.
This project is licensed under the Apache License. See the LICENSE file for the license text.
Developer Experience engineering team: team-developer-experience@sinch.com