Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
b5bf149
DEVEXP-1618: Add Voice v2 calls.start (createCall) endpoint
edu-sinch Sep 24, 2026
f1a7ff6
DEVEXP-1618: Add Voice v2 batches.start (createCall) endpoint
edu-sinch Sep 24, 2026
cb3c9c6
DEVEXP-1618: Address PR review comments
edu-sinch Sep 28, 2026
9aff8ba
DEVEXP-1618: Split SVAML models into category subpackages
edu-sinch Sep 28, 2026
5b2b810
DEVEXP-1618: Address PR review comments on enums and Voice V2 regions
edu-sinch Sep 28, 2026
c2d932a
DEVEXP-1618: Address PR review comments on models, helpers and tests
edu-sinch Sep 28, 2026
9448887
Write batch snippet parameters by hand and alignment with the rest of…
edu-sinch Sep 28, 2026
4ae8598
DEVEXP-1618: Add Voice API v2 to the README
edu-sinch Sep 28, 2026
ac35fc1
DEVEXP-404: Extend Voice and Verification test validation coverage
edu-sinch Aug 20, 2026
64b6885
DEVEXP-404: Address PR review comments
edu-sinch Sep 28, 2026
96c1663
DEVEXP-1526: Extend SinchClient configuration with transport level se…
edu-sinch Aug 21, 2026
03e667a
DEVEXP-1526: Address PR review comments
edu-sinch Sep 28, 2026
3573d1c
Merge pull request #47 from sinch/edu-sinch/DEVEXP-404-CoverageForVal…
edu-sinch Sep 29, 2026
a6952e9
Merge remote-tracking branch 'internal-upstream/edu-sinch/Voice-V2-Im…
edu-sinch Sep 29, 2026
5175873
DEVEXP-1618: Address PR review comments on regions, configuration, do…
edu-sinch Sep 29, 2026
813901f
Address the pending comments
edu-sinch Sep 29, 2026
caa4bca
Merge branch 'feat/V2.3-next' into edu-sinch/DEVEXP-1526-ExtendSinchC…
edu-sinch Sep 30, 2026
acefce8
Bump com.fasterxml.jackson.core:jackson-databind from 2.21.5 to 2.21.…
dependabot[bot] Sep 30, 2026
b85f5ce
DEVEXP-1618: Remove idempotency key generation, name based region loo…
edu-sinch Oct 1, 2026
ee00043
DEVEXP-1526: Address PR review comments
edu-sinch Oct 1, 2026
52a5650
DEVEXP-1526: Remove duplicated default timeout test
edu-sinch Oct 1, 2026
04d47cd
DEVEXP-1618: Map Voice V2 error responses and snippet modification
edu-sinch Oct 5, 2026
ac2bc07
Merge pull request #53 from sinch/edu-sinch/DEVEXP-1618-VoiceV2Create…
edu-sinch Oct 5, 2026
1514280
DEVEXP-1623: Add Voice v2 batches.get endpoint
edu-sinch Oct 5, 2026
5b0ad59
DEVEXP-1623: Add Voice v2 batches.stop endpoint
edu-sinch Oct 6, 2026
d61fd3b
DEVEXP-1623: Add Voice v2 batches.getDetails endpoint
edu-sinch Oct 6, 2026
605b1a8
DEVEXP-1623: Add Voice v2 sessions.get endpoint
edu-sinch Oct 6, 2026
03b7f33
Aligned of a variable in the BatchesServiceTest
edu-sinch Oct 6, 2026
b5da643
Merge pull request #56 from sinch/edu-sinch/DEVEXP-1623-VoiceV2Batche…
edu-sinch Oct 6, 2026
ed7ec56
DEVEXP-1624: Add Voice v2 Sinch Events
edu-sinch Oct 7, 2026
c1cc151
Add Voice v2 calls.get endpoint
edu-sinch Oct 8, 2026
9b56b72
Add Voice v2 calls.list endpoint
edu-sinch Oct 8, 2026
9cee535
Add Voice v2 calls.interactByCallId endpoint
edu-sinch Oct 8, 2026
b6fad0d
Add Voice v2 calls.interactByCallName endpoint
edu-sinch Oct 8, 2026
1e5578e
DEVEXP-1624: Add VoiceSinchEventResponse and rename SvamlInputEvents …
edu-sinch Oct 8, 2026
05ccc66
Merge pull request #57 from sinch/edu-sinch/DEVEXP-1624-VoiceV2SinchE…
edu-sinch Oct 8, 2026
940d799
Merge pull request #58 from sinch/edu-sinch/VoiceV2CallManagement
edu-sinch Oct 9, 2026
5c54b52
Add Voice v2 services.create endpoint
edu-sinch Oct 8, 2026
33e4aa4
Add Voice v2 services.get endpoint
edu-sinch Oct 8, 2026
fb91faa
Add Voice v2 services.list endpoint
edu-sinch Oct 8, 2026
9c37e92
Add Voice v2 services.update endpoint
edu-sinch Oct 8, 2026
a25147a
Add Voice v2 services.delete endpoint
edu-sinch Oct 8, 2026
150ec96
Use setAsDefault on service update and Java SDK names in services sni…
edu-sinch Oct 9, 2026
68648f4
Merge pull request #59 from sinch/edu-sinch/VoiceV2Services
edu-sinch Oct 9, 2026
ce145e5
Add Voice v2 svaml.describe endpoint
edu-sinch Oct 9, 2026
708a0c0
Add Voice v2 svaml.validate endpoint
edu-sinch Oct 9, 2026
499a2ec
DEVEXP-1630: Generate the Idempotency-Key in the transport
edu-sinch Oct 9, 2026
f677d99
Merge pull request #60 from sinch/edu-sinch/VoiceV2Payloads
edu-sinch Oct 9, 2026
9994f5a
Merge pull request #61 from sinch/edu-sinch/DEVEXP-1630-IdempotencyKey
edu-sinch Oct 9, 2026
3fd3764
DEVEXP-1707: Align Voice V2 with the batches endpoint split and menu …
edu-sinch Oct 14, 2026
d62f72a
Removed entries in CHANGELOG not rquired
edu-sinch Oct 14, 2026
454b2f1
Merge pull request #62 from sinch/edu-sinch/DEVEXP-1707-VoiceV2Batche…
edu-sinch Oct 14, 2026
15af2a4
docs: Recommend Voice API v2 for new projects
edu-sinch Oct 15, 2026
71dec5b
Merge pull request #63 from sinch/edu-sinch/VoiceV2ReadmeGuidance
edu-sinch Oct 15, 2026
16baa98
Merge branch 'feat/V2.3-next' into edu-sinch/Voice-V2-Implementation
edu-sinch Oct 15, 2026
236baf7
Merge pull request #64 from sinch/edu-sinch/Voice-V2-Implementation
edu-sinch Oct 15, 2026
b04de39
Merge branch 'feat/V2.3-next' into edu-sinch/DEVEXP-1526-ExtendSinchC…
edu-sinch Oct 15, 2026
2aca8c9
DEVEXP-1526: Pass the timeout to HttpClientApache in the Idempotency-…
edu-sinch Oct 15, 2026
8076b08
Merge pull request #49 from sinch/edu-sinch/DEVEXP-1526-ExtendSinchCl…
edu-sinch Oct 15, 2026
50a93a9
Bump Jackson to 2.21.7 to fix Dependabot vulnerabilities
edu-sinch Oct 15, 2026
290fc1e
Merge pull request #366 from sinch/edu-sinch/DEVEXP-DependantBotVulne…
edu-sinch Oct 15, 2026
3c3a11f
Bump central-publishing-maven-plugin to 0.12.0 to fix Central bundle …
edu-sinch Oct 15, 2026
3d95485
Merge pull request #65 from sinch/edu-sinch/DEVEXP-CentralPublishingP…
edu-sinch Oct 15, 2026
06f9a3f
build (release): Bump version to 2.3.0 for sources
invalid-email-address Oct 15, 2026
32cce41
[release] Set release & tag: 2.3.0
invalid-email-address Oct 15, 2026
213b23b
[release] Set next version: 2.4.0-SNAPSHOT
invalid-email-address Oct 15, 2026
762bc89
build (release): Set next version to 2.4.0-dev for sources
invalid-email-address Oct 15, 2026
acc92d9
Update README.md
edu-sinch Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@ All notable changes to the **Sinch Java SDK** are documented in this file.
> - `[tech]` — technical improvement

---
## v2.3.0 - 2026-10-15

### Voice
- **[feature]** Support [Voice API v2](https://developers.sinch.com/docs/voice-2.0), exposed under `voice().v2()`
- **[feature]** Support V2 `Calls` API: `start`, `get`, `list`, `interactByCallId` and `interactByCallName` endpoints
- **[feature]** Support V2 `Batches` API: `start`, `get`, `getDetails` and `stop` endpoints
- **[feature]** Support V2 `Sessions` API: `get` endpoint
- **[feature]** Support V2 `Services` API: `create`, `get`, `list`, `update` and `delete` endpoints
- **[feature]** Support V2 `SVAML` API: `describe` and `validate` endpoints
- **[feature]** Support V2 Sinch Events: `validateAuthenticationHeader`, `parseEvent` and `serializeResponse`
- **[doc]** Snippets for every Voice V2 endpoint, under `voice/v2/`
- **[doc]** `sinch-events` example: new Voice V2 Sinch Events controller on `/VoiceV2Event`
- **[test]** Extend V1 `SinchEventsService.validateAuthenticationHeader` coverage

### SDK
- **[feature]** `SinchClient` transport level settings: `TransportSettings` (`timeoutSeconds`, `useSinchAuth`)
- **[feature]** `Idempotency-Key` support: for the operations that accept the header, the SDK generates a key when none is set and sends the same key on the `HTTP 429` retries of a call
- **[test]** Extend `ApplicationAuthManager` signed request validation coverage

### Verification
- **[test]** Extend `SinchEventsService.validateAuthenticationHeader` coverage

### Build
- **[dependency]** Bump `jackson.version` to `2.21.7` to solve denial-of-service and unsafe deserialization vulnerabilities in `jackson-databind` (CVE-2026-19032, CVE-2026-68497, CVE-2026-83557, CVE-2026-91776 and CVE-2026-91777).
- **[releasing]** Bump `central-publishing-maven-plugin` to `0.12.0`: Maven Central rejected the release bundle built with Apache Maven 3.10.0

## v2.2.0 - 2026-09-17

### SDK
Expand Down
62 changes: 60 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ To use Sinch services, you'll need a Sinch account and access keys. You can sign
- [Handling Exceptions](#handling-exceptions)
- [Proxy configuration](#proxy-configuration)
- [Retry configuration](#retry-configuration)
- [Transport settings](#transport-settings)
- [Third-party dependencies](#third-party-dependencies)
- [Examples](#examples)
- [Changelog and Migration](#changelog--migration)
Expand Down Expand Up @@ -107,6 +108,7 @@ Note: The `${sdk.version}` needs to be set according to the released version to
| Messaging | [Conversation API](https://developers.sinch.com/docs/conversation/) |
| | [SMS API](https://developers.sinch.com/docs/sms/) |
| Voice and Video | [Voice API](https://developers.sinch.com/docs/voice/) |
| | [Voice API v2](https://developers.sinch.com/docs/voice-2.0) |
| Numbers | [Numbers API](https://developers.sinch.com/docs/numbers/) |
| Verification | [Verification API](https://developers.sinch.com/docs/verification/) |
| | [Number Lookup API](https://developers.sinch.com/docs/number-lookup-api-v2/) |
Expand Down Expand Up @@ -316,7 +318,17 @@ You can find a complete example in [examples/sinch-events](https://github.com/si

### Voice API

The Voice API uses application credentials. Set `applicationKey` and `applicationSecret` (both available on the [Apps dashboard](https://dashboard.sinch.com/voice/apps)); `voiceRegion` is optional and defaults to a global region:
**Note:** For all new projects, please use Voice API v2. This is especially important for projects involving:

- AI capabilities like Streams and Voice Relay
- Voice campaigns like Batch calling

You should only use the older Voice API v1 if one of the following is a strict requirement:

- The project must be in General Availability (GA).
- The project requires In-App voice or Conferencing (until these features are available in v2).

The Voice API v1 uses application credentials. Set `applicationKey` and `applicationSecret` (both available on the [Apps dashboard](https://dashboard.sinch.com/voice/apps)); `voiceRegion` is optional and defaults to a global region:

```java
import com.sinch.sdk.SinchClient;
Expand All @@ -335,7 +347,7 @@ SinchClient client = new SinchClient(configuration);

#### Sinch Events

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`:
The Voice API v1 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`:

```java
import com.sinch.sdk.domains.voice.api.v1.SinchEventsService;
Expand All @@ -351,6 +363,12 @@ Some events (for example an incoming call) expect a SVAML response: build it fro

You can find a complete example in [examples/sinch-events](https://github.com/sinch/sinch-sdk-java/tree/main/examples/sinch-events).

#### Voice API v2

> **Note:** Support for the Voice API v2 is currently in preview.

The Voice API v2 needs no extra parameters, use the [common client](#client-initialization) shown above.


### Your first request

Expand Down Expand Up @@ -542,6 +560,46 @@ Configuration configuration = Configuration.builder()
SinchClient client = new SinchClient(configuration);
```

## Transport settings

`SinchClient` accepts optional transport-level settings alongside credentials. They apply to product API calls and to OAuth token fetches.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `timeoutSeconds` | `int` | `60` | HTTP I/O timeout in seconds. Pass `0` to disable the timeout. Negative values are rejected. |
| `useSinchAuth` | `boolean` | `true` | When `true`, OAuth-capable APIs fetch a Sinch access token. Set `false` to disable Sinch authentication: no token is fetched and no `Authorization` header is added. With unified credentials only `projectId` is then required. Has no effect with SMS service plan credentials. |

### Timeout

```java
import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.TransportSettings;

...
Configuration configuration = Configuration.builder()
...
.setTransportSettings(
TransportSettings.builder()
.setTimeoutSeconds(30)
.build())
.build();
SinchClient client = new SinchClient(configuration);
```

### Disable Sinch OAuth

```java
Configuration configuration = Configuration.builder()
...
.setTransportSettings(
TransportSettings.builder()
.setUseSinchAuth(false)
.build())
.build();
SinchClient client = new SinchClient(configuration);
```

## Third-party dependencies
The SDK relies on the following third-party dependencies:
- [Jackson](https://github.com/FasterXML/jackson-jakarta-rs-providers): provides JSON serialization/deserialization functionality.
Expand Down
8 changes: 8 additions & 0 deletions client/resources/config-default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ voice-server-south-america=https://calling-sae1.api.sinch.com
voice-server-south-east-asia1=https://calling-apse1.api.sinch.com
voice-server-south-east-asia2=https://calling-apse2.api.sinch.com

voice-v2-region=global
voice-v2-server-global=https://voice.api.sinch.com
voice-v2-server-us1=https://us1.voice.api.sinch.com
voice-v2-server-br1=https://br1.voice.api.sinch.com
voice-v2-server-eu1=https://eu1.voice.api.sinch.com
voice-v2-server-sg1=https://sg1.voice.api.sinch.com
voice-v2-server-au1=https://au1.voice.api.sinch.com

conversation-region=
conversation-server=https://%s.conversation.api.sinch.com
template-management-conversation-server=https://%s.template.api.sinch.com
Expand Down
2 changes: 1 addition & 1 deletion client/src/main/com/sinch/sdk/SDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
public class SDK {

public static final String NAME = "Sinch Java SDK";
public static final String VERSION = "2.3.0-dev";
public static final String VERSION = "2.4.0-dev";
public static final String AUXILIARY_FLAG = "";
}
68 changes: 63 additions & 5 deletions client/src/main/com/sinch/sdk/SinchClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.sinch.sdk.models.NumbersContext;
import com.sinch.sdk.models.SMSRegion;
import com.sinch.sdk.models.SmsContext;
import com.sinch.sdk.models.TransportSettings;
import com.sinch.sdk.models.VerificationContext;
import com.sinch.sdk.models.VoiceContext;
import com.sinch.sdk.models.VoiceRegion;
Expand Down Expand Up @@ -46,6 +47,7 @@ public class SinchClient {
private static final String VOICE_REGION_KEY = "voice-region";
private static final String VOICE_APPLICATION_MANAGEMENT_SERVER_KEY =
"voice-application-management-server";
private static final String VOICE_V2_REGION_KEY = "voice-v2-region";

private static final String VERIFICATION_SERVER_KEY = "verification-server";

Expand Down Expand Up @@ -94,6 +96,7 @@ public SinchClient(Configuration configuration) {
handleDefaultSmsSettings(configurationGuard, props, builder);
handleDefaultVerificationSettings(configurationGuard, props, builder);
handleDefaultVoiceSettings(configurationGuard, props, builder);
handleDefaultVoiceV2Settings(configurationGuard, props, builder);
handleDefaultConversationSettings(configurationGuard, props, builder);
handleDefaultNumberLookupSettings(configurationGuard, props, builder);

Expand Down Expand Up @@ -210,6 +213,45 @@ private void handleDefaultVoiceSettings(
}
}

private void handleDefaultVoiceV2Settings(
Configuration configuration, Properties props, Configuration.Builder builder) {

com.sinch.sdk.domains.voice.models.v2.VoiceRegion region =
configuration
.getVoiceV2Context()
.map(com.sinch.sdk.domains.voice.models.v2.VoiceContext::getVoiceRegion)
.orElse(null);

String voiceUrl =
configuration
.getVoiceV2Context()
.map(com.sinch.sdk.domains.voice.models.v2.VoiceContext::getVoiceUrl)
.orElse(null);

// default region to be used ?
if (null == region && props.containsKey(VOICE_V2_REGION_KEY)) {
region =
com.sinch.sdk.domains.voice.models.v2.VoiceRegion.from(
props.getProperty(VOICE_V2_REGION_KEY));
}

// server is not defined: use the region to set to an existing one and use "global" as a default
// fallback
if (StringUtil.isEmpty(voiceUrl)) {
com.sinch.sdk.domains.voice.models.v2.VoiceRegion regionForFormat =
null == region ? com.sinch.sdk.domains.voice.models.v2.VoiceRegion.GLOBAL : region;
voiceUrl = props.getProperty(String.format("voice-v2-server-%s", regionForFormat.value()));
}

if (null != region || null != voiceUrl) {
builder.setVoiceV2Context(
com.sinch.sdk.domains.voice.models.v2.VoiceContext.builder()
.setVoiceRegion(region)
.setVoiceUrl(voiceUrl)
.build());
}
}

private void handleDefaultConversationSettings(
Configuration configuration, Properties props, Configuration.Builder builder) {

Expand Down Expand Up @@ -379,12 +421,21 @@ private void checkConfiguration(Configuration configuration) throws NullPointerE
Objects.requireNonNull(configuration.getOAuthUrl(), "'oauthUrl' cannot be null");
}

private TransportSettings transportSettings() {
return configuration.getTransportSettings().orElse(TransportSettings.DEFAULTS);
}

private boolean useSinchAuth() {
return transportSettings().getUseSinchAuth();
}

private NumbersService numbersInit() {
return new com.sinch.sdk.domains.numbers.adapters.NumbersService(
getConfiguration().getUnifiedCredentials().orElse(null),
configuration.getNumbersContext().orElse(null),
configuration.getOAuthServer(),
this::getHttpClient);
this::getHttpClient,
useSinchAuth());
}

private SMSService smsInit() {
Expand All @@ -401,7 +452,8 @@ f, getConfiguration().getSmsContext().orElse(null), this::getHttpClient))
getConfiguration().getUnifiedCredentials().orElse(null),
getConfiguration().getSmsContext().orElse(null),
configuration.getOAuthServer(),
this::getHttpClient));
this::getHttpClient,
useSinchAuth()));
}

private VerificationService verificationInit() {
Expand All @@ -414,7 +466,10 @@ private VerificationService verificationInit() {
private VoiceService voiceInit() {
return new com.sinch.sdk.domains.voice.adapters.VoiceService(
getConfiguration().getApplicationCredentials().orElse(null),
getConfiguration().getUnifiedCredentials().orElse(null),
getConfiguration().getVoiceContext().orElse(null),
getConfiguration().getVoiceV2Context().orElse(null),
getConfiguration().getOAuthServer(),
this::getHttpClient);
}

Expand All @@ -423,15 +478,17 @@ private ConversationService conversationInit() {
getConfiguration().getUnifiedCredentials().orElse(null),
getConfiguration().getConversationContext().orElse(null),
getConfiguration().getOAuthServer(),
this::getHttpClient);
this::getHttpClient,
useSinchAuth());
}

private NumberLookupService lookupInit() {
return new com.sinch.sdk.domains.numberlookup.adapters.NumberLookupService(
getConfiguration().getUnifiedCredentials().orElse(null),
getConfiguration().getNumberLookupContext().orElse(null),
getConfiguration().getOAuthServer(),
this::getHttpClient);
this::getHttpClient,
useSinchAuth());
}

private Properties handlePropertiesFile(String fileName) {
Expand All @@ -454,7 +511,8 @@ private HttpClient getHttpClient() {
local =
new HttpClientApache(
configuration.getHttpProxyConfiguration().orElse(null),
new DefaultRetryManager(configuration.getRetryConfiguration().orElse(null)));
new DefaultRetryManager(configuration.getRetryConfiguration().orElse(null)),
transportSettings().getTimeoutSeconds());

// set SDK User-Agent
String userAgent = formatSdkUserAgentHeader();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class ConversationService implements com.sinch.sdk.domains.conversation.C
private final ConversationContext context;
private final ServerConfiguration oAuthServer;
private final Supplier<HttpClient> httpClientSupplier;
private final boolean useSinchAuth;

private volatile com.sinch.sdk.domains.conversation.api.v1.ConversationService conversationV1;
private volatile TemplatesService templates;
Expand All @@ -21,11 +22,13 @@ public ConversationService(
UnifiedCredentials credentials,
ConversationContext context,
ServerConfiguration oAuthServer,
Supplier<HttpClient> httpClientSupplier) {
Supplier<HttpClient> httpClientSupplier,
boolean useSinchAuth) {
this.credentials = credentials;
this.context = context;
this.oAuthServer = oAuthServer;
this.httpClientSupplier = httpClientSupplier;
this.useSinchAuth = useSinchAuth;
}

public com.sinch.sdk.domains.conversation.api.v1.ConversationService v1() {
Expand All @@ -34,7 +37,7 @@ public com.sinch.sdk.domains.conversation.api.v1.ConversationService v1() {
if (null == this.conversationV1) {
this.conversationV1 =
new com.sinch.sdk.domains.conversation.api.v1.adapters.ConversationService(
credentials, context, oAuthServer, httpClientSupplier);
credentials, context, oAuthServer, httpClientSupplier, useSinchAuth);
}
}
}
Expand All @@ -46,7 +49,8 @@ public TemplatesService templates() {
synchronized (this) {
if (null == this.templates) {
this.templates =
new TemplatesService(credentials, context, oAuthServer, httpClientSupplier);
new TemplatesService(
credentials, context, oAuthServer, httpClientSupplier, useSinchAuth);
}
}
}
Expand Down
Loading
Loading