# Handle an incoming call with Java SDK Now that you know how to [call yourself using the Voice API](/docs/voice/getting-started/java-sdk/make-call), learn how to handle incoming calls. Note: Before you can get started, you need the following already set up: - Set all Voice API [configuration settings](/docs/voice/getting-started). - [JDK 21 or later](https://www.oracle.com/java/technologies/downloads/). While the Java SDK itself requires JDK 8 or later, this application uses the latest RTS version of Java. - [Apache Maven](https://maven.apache.org/install.html) and a familiarity with how to use the Maven CLI. ## Step 1. Set up your Java application To quickly get started setting up a simple client application using the Java SDK: 1. If you haven't already, clone the [sinch-sdk-java-quickstart](https://github.com/sinch/sinch-sdk-java-quickstart) repository. 2. Navigate to the `getting-started/voice/respond-to-incoming-call/server/src/main/resources` folder. 3. Open the `application.yaml` [file](https://github.com/sinch/sinch-sdk-java-quickstart/blob/main/getting-started/voice/respond-to-incoming-call/server/src/main/resources/application.yaml). Using the [Voice app credentials](https://dashboard.sinch.com/voice/apps) from your Sinch Build Dashboard, add your values: | Field | Description | | --- | --- | | APPLICATION_API_KEY | The unique ID of your application. | | APPLICATION_API_SECRET | The secret for your application. | 4. Save the file. The code containing the business logic for responding to an incoming call is provided here for reference. ServerBusinessLogic.java // Use this code to handle an incoming call using the Voice API and the Java SDK. package com.mycompany.app.voice; import com.sinch.sdk.domains.voice.models.v1.svaml.SvamlControl; import com.sinch.sdk.domains.voice.models.v1.svaml.action.SvamlActionHangup; import com.sinch.sdk.domains.voice.models.v1.svaml.instruction.SvamlInstructionSay; import com.sinch.sdk.domains.voice.models.v1.webhooks.DisconnectedCallEvent; import com.sinch.sdk.domains.voice.models.v1.webhooks.IncomingCallEvent; import java.util.Collections; import java.util.logging.Logger; import org.springframework.stereotype.Component; @Component("VoiceServerBusinessLogic") public class ServerBusinessLogic { private static final Logger LOGGER = Logger.getLogger(ServerBusinessLogic.class.getName()); public SvamlControl incoming(IncomingCallEvent event) { LOGGER.info("Handle event: " + event); String instruction = "Thank you for calling your Sinch number. You've just handled an incoming call."; return SvamlControl.builder() .setAction(SvamlActionHangup.builder().build()) .setInstructions( Collections.singletonList(SvamlInstructionSay.builder().setText(instruction).build())) .build(); } public void disconnect(DisconnectedCallEvent event) { LOGGER.info("Handle event: " + event); } } ## Step 2. Start your web server and set up a tunnel 1. Open a terminal or command prompt to the `getting-started/voice/respond-to-incoming-call/server` folder, and start the server by executing the following command: ```shell Start server mvn clean spring-boot:run ``` 2. Open a tunnel to the server you just set up. We are using [ngrok](https://ngrok.com/) for this. If you don't have ngrok installed already, install it with the following command: ```shell Install ngrok npm install ngrok -g ``` 3. Open a second terminal or command prompt and enter: ```shell Start ngrok ngrok http 8090 ``` By default, the Springboot server is listening on port 8090. If you need to change this, you can modify the port in the `application.yaml` file. If you change the port, make sure you start your ngrok tunnel on that port instead. In your console you will see an ngrok URL. Copy that URL and append `/VoiceEvent` to the end of it so that it looks something like `/VoiceEvent`. 4. Navigate to your app on your [dashboard](https://dashboard.sinch.com/voice/apps). Under the **Settings** section, you'll see a field labeled "Callback URL." Enter your URL into that field and click **Save**. Now your server is listening and your callback URL is configured, so you're almost ready to test everything and make a phone call. But before we do, let's take a closer look at callbacks. If you already know about callbacks, skip right to [calling your Sinch phone number](#call-your-sinch-phone-number). ### Understanding callbacks Callbacks (also known as "webhooks") are the method that the Voice API uses to figure out what you want to do with a call. Basically, a [callback](/docs/voice/api-reference/voice/callbacks) is a request that the Sinch servers send to your server whenever something happens (otherwise known as an "event") in the call that requires some input from you. There are a few different types of events, but the two we are concerned about for this guide are the Incoming Call Event and the Disconnected Call Event. An *Incoming Call Event* happens whenever someone calls one of your Sinch numbers. In essence, someone dials your number and so Sinch servers reach out to you and say "how do you want me to handle this call?" Most callback events expect a response, depending on the event. The *Incoming Call Event* expects to receive back a SVAML object in response. You can read more about SVAML [here](/docs/voice/api-reference/svaml/), but just know that SVAML is a markup language Sinch developed to control calls. The below diagram demonstrates exactly what's happening: ![incoming call diagram](/assets/handle-incoming-call.3809082ae39152f6e98c443d3a86028669782ded822c95e224a9939a0a4b9e58.c78575ff.png) 1. Someone dials your Sinch number from a handset. 2. The Sinch servers create an ICE and send a POST request to your server. 3. Your server listens for the request and sends back a SVAML response to tell the Sinch server how to handle the call. In this sample application, this is the SVAML object that you will use to respond to the callback (we've also provided the underlying JSON SVAML object for comparison): SDK ```java SDK public SVAMLControl incoming(IncomingCallEvent event) { LOGGER.info("Handle event: " + event); String instruction = "Thank you for calling your Sinch number. You've just handled an incoming call."; return SVAMLControl.builder() .setAction(ActionHangUp.builder().build()) .setInstructions( Collections.singletonList(InstructionSay.builder().setText(instruction).build())) .build(); } ``` JSON ```json JSON { "instructions": [ { "name": "say", "text": "Thank you for calling your Sinch number. You've just handled an incoming call", "local": "en-US" } ], "action": { "name": "hangup" } } ``` This SVAML object has two parts: instructions and an action. Instructions are things you want to be done on the call without changing the state of the call. In this case, we want to play a voice that reads out a text message. Actions are things you want to be done to the call to change its state in some way. In this case, we want to hang up and end the call. Note: When using the Java SDK, you must [serialize the SVAMLControl response](https://developers.sinch.com/java-sdk/apidocs/com/sinch/sdk/domains/voice/webhooksservice.html#serializewebhooksresponse(com.sinch.sdk.domains.voice.models.svaml.svamlcontrol)) object before returning it to the Sinch server, as in the following example: ```java serializeWebhooksResponse voiceService.webhooks().serializeWebhooksResponse(response); ``` In this application, that is handled in the `Controller.java` [file](https://github.com/sinch/sinch-sdk-java-quickstart/blob/main/getting-started/voice/respond-to-incoming-call/server/src/main/java/com/mycompany/app/voice/Controller.java). And that's it! Now we can test. ## Step 3. Call your Sinch phone number Look up the free Sinch number assigned to your app and call it using your phone. The call should be picked up by the Sinch servers and you should hear the text from the instruction. Now you know how to handle an incoming call. ## Next steps Learn more about the Voice API: - [API specification](/docs/voice/api-reference/voice)