diff --git a/client/src/main/com/sinch/sdk/domains/sms/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/SMSService.java
index 2947577e..daa31986 100644
--- a/client/src/main/com/sinch/sdk/domains/sms/SMSService.java
+++ b/client/src/main/com/sinch/sdk/domains/sms/SMSService.java
@@ -16,4 +16,12 @@ public interface SMSService {
* @since 1.0
*/
BatchesService batches();
+
+ /**
+ * WebHooksService Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ WebHooksService webHooks();
}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/WebHooksService.java b/client/src/main/com/sinch/sdk/domains/sms/WebHooksService.java
new file mode 100644
index 00000000..e412a587
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/WebHooksService.java
@@ -0,0 +1,58 @@
+package com.sinch.sdk.domains.sms;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.sms.models.webhooks.BaseIncomingSMS;
+
+/**
+ * SMS WebHooks
+ *
+ *
Callbacks
+ *
+ *
A callback is an HTTP POST request with a notification made by the Sinch SMS REST API to a URI
+ * of your choosing.
+ *
+ *
The REST API expects the receiving server to respond with a response code within the 2xx
+ * success range. For 5xx the callback will be retried. For 429 the callback will be retried and the
+ * throughput will be lowered. For other status codes in the 4xx range the callback will not be
+ * retried. The first initial retry will happen 5 seconds after the first try. The next attempt is
+ * after 10 seconds, then after 20 seconds, after 40 seconds, after 80 seconds, doubling on every
+ * attempt. The last retry will be at 81920 seconds (or 22 hours 45 minutes) after the initial
+ * failed attempt.
+ *
+ *
The SMS REST API offers the following callback options which can be configured for your
+ * account upon request to your account manager.
+ *
+ *
+ * - Callback with mutual authentication over TLS (HTTPS) connection by provisioning the
+ * callback URL with client keystore and password.
+ *
- Callback with basic authentication by provisioning the callback URL with username and
+ * password.
+ *
- Callback with OAuth 2.0 by provisioning the callback URL with username, password and the
+ * URL to fetch OAuth access token.
+ *
- Callback using AWS SNS by provisioning the callback URL with an Access Key ID, Secret Key
+ * and Region.
+ *
+ *
+ * @see https://developers.sinch.com/docs/sms/api-reference/sms/tag/Webhooks/
+ * @since 1.0
+ */
+public interface WebHooksService {
+
+ /**
+ * Incoming SMSWebhook
+ *
+ * An inbound message is a message sent to one of your short codes or long numbers from a
+ * mobile phone. To receive inbound message callbacks, a URL needs to be added to your REST API.
+ * This URL can be specified in your @link https://dashboard.sinch.com/sms/api.
+ *
+ * @param jsonPayload The incoming message to your sinch number
+ * @param A type of Batch
+ * @return Decoded payload
+ * @see https://developers.sinch.com/docs/sms/api-reference/sms/tag/Webhooks/#tag/Webhooks/operation/incomingSMS
+ * @since 1.0
+ */
+ > T incomingSMS(String jsonPayload) throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
index fd2f3a26..bbc23470 100644
--- a/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
@@ -2,6 +2,7 @@
import com.sinch.sdk.core.http.HttpClient;
import com.sinch.sdk.domains.sms.BatchesService;
+import com.sinch.sdk.domains.sms.WebHooksService;
import com.sinch.sdk.models.Configuration;
public class SMSService implements com.sinch.sdk.domains.sms.SMSService {
@@ -9,6 +10,7 @@ public class SMSService implements com.sinch.sdk.domains.sms.SMSService {
private final Configuration configuration;
private final HttpClient httpClient;
private BatchesService batches;
+ private WebHooksService webHooks;
public SMSService(Configuration configuration, HttpClient httpClient) {
this.configuration = configuration;
@@ -23,4 +25,12 @@ public BatchesService batches() {
}
return this.batches;
}
+
+ @Override
+ public WebHooksService webHooks() {
+ if (null == this.webHooks) {
+ this.webHooks = new com.sinch.sdk.domains.sms.adapters.WebHooksService();
+ }
+ return this.webHooks;
+ }
}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/WebHooksService.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/WebHooksService.java
new file mode 100644
index 00000000..bac5184d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/WebHooksService.java
@@ -0,0 +1,25 @@
+package com.sinch.sdk.domains.sms.adapters;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.sinch.sdk.core.exceptions.ApiMappingException;
+import com.sinch.sdk.core.utils.StringUtil;
+import com.sinch.sdk.core.utils.databind.Mapper;
+import com.sinch.sdk.domains.sms.models.webhooks.BaseIncomingSMS;
+
+public class WebHooksService implements com.sinch.sdk.domains.sms.WebHooksService {
+
+ @Override
+ public > T incomingSMS(String jsonPayload)
+ throws ApiMappingException {
+ try {
+ @SuppressWarnings("unchecked")
+ T generic = (T) Mapper.getInstance().readValue(jsonPayload, BaseIncomingSMS.class);
+ if (null == generic && !StringUtil.isEmpty(jsonPayload)) {
+ throw new ApiMappingException(jsonPayload, null);
+ }
+ return generic;
+ } catch (JsonProcessingException e) {
+ throw new ApiMappingException(jsonPayload, e);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/BaseIncomingSMS.java b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/BaseIncomingSMS.java
new file mode 100644
index 00000000..7fde29c9
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/BaseIncomingSMS.java
@@ -0,0 +1,98 @@
+package com.sinch.sdk.domains.sms.models.webhooks;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.util.Optional;
+
+/**
+ * Base class for Incoming SMSWebhook
+ *
+ * @param Type of SMS body
+ * @since 1.0
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.EXISTING_PROPERTY,
+ property = "type",
+ visible = true)
+@JsonSubTypes({
+ @JsonSubTypes.Type(value = IncomingSMSBinary.class, name = "mo_binary"),
+ @JsonSubTypes.Type(value = IncomingSMSText.class, name = "mo_text")
+})
+public abstract class BaseIncomingSMS {
+
+ static final String JSON_PROPERTY_BODY = "body";
+ private final T body;
+ static final String JSON_PROPERTY_FROM = "from";
+ private final String from;
+ static final String JSON_PROPERTY_ID = "id";
+ private final String id;
+ static final String JSON_PROPERTY_RECEIVED_AT = "received_at";
+ private final Instant receivedAt;
+ static final String JSON_PROPERTY_TO = "to";
+ private final String to;
+ static final String JSON_PROPERTY_CLIENT_REFERENCE = "client_reference";
+ private final String clientReference;
+ static final String JSON_PROPERTY_OPERATOR_ID = "operator_id";
+ private final String operatorId;
+ static final String JSON_PROPERTY_SENT_AT = "sent_at";
+ private final Instant sentAt;
+
+ @JsonCreator
+ public BaseIncomingSMS(
+ @JsonProperty(JSON_PROPERTY_BODY) T body,
+ @JsonProperty(JSON_PROPERTY_FROM) String from,
+ @JsonProperty(JSON_PROPERTY_ID) String id,
+ @JsonProperty(JSON_PROPERTY_RECEIVED_AT) OffsetDateTime receivedAt,
+ @JsonProperty(JSON_PROPERTY_TO) String to,
+ @JsonProperty(JSON_PROPERTY_CLIENT_REFERENCE) String clientReference,
+ @JsonProperty(JSON_PROPERTY_OPERATOR_ID) String operatorId,
+ @JsonProperty(JSON_PROPERTY_SENT_AT) OffsetDateTime sentAt) {
+ this.body = body;
+ this.from = from;
+ this.id = id;
+ this.receivedAt = receivedAt.toInstant();
+ this.to = to;
+ this.clientReference = clientReference;
+ this.operatorId = operatorId;
+ this.sentAt = null != sentAt ? sentAt.toInstant() : null;
+ }
+
+ public T getBody() {
+ return body;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Instant getReceivedAt() {
+ return receivedAt;
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public Optional getClientReference() {
+ return Optional.ofNullable(clientReference);
+ }
+
+ public Optional getOperatorId() {
+ return Optional.ofNullable(operatorId);
+ }
+
+ public Optional getSentAt() {
+ return Optional.ofNullable(sentAt);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSBinary.java b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSBinary.java
new file mode 100644
index 00000000..80127924
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSBinary.java
@@ -0,0 +1,53 @@
+package com.sinch.sdk.domains.sms.models.webhooks;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.OffsetDateTime;
+
+public class IncomingSMSBinary extends BaseIncomingSMS {
+
+ static final String JSON_PROPERTY_UDH = "udh";
+ private final String udh;
+
+ /**
+ * Binary MO class
+ *
+ * @param body The message content Base64 encoded. Max 140 bytes together with udh.
+ * @param from The phone number that sent the message. @see https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628
+ * @param id The ID of this inbound message.
+ * @param receivedAt When the system received the message.
+ * @param to The Sinch phone number or short code to which the message was sent.
+ * @param clientReference If this inbound message is in response to a previously sent message that
+ * contained a client reference, then this field contains that client reference. Utilizing
+ * this feature requires additional setup on your account. Contact your account manager to
+ * enable this feature.
+ * @param operatorId The MCC/MNC of the sender's operator if known.
+ * @param sendAt When the message left the originating device. Only available if provided by
+ * operator.
+ * @param udh The UDH header of a binary message HEX encoded. Max 140 bytes together with body.
+ */
+ @JsonCreator
+ public IncomingSMSBinary(
+ @JsonProperty(JSON_PROPERTY_BODY) String body,
+ @JsonProperty(JSON_PROPERTY_FROM) String from,
+ @JsonProperty(JSON_PROPERTY_ID) String id,
+ @JsonProperty(JSON_PROPERTY_RECEIVED_AT) OffsetDateTime receivedAt,
+ @JsonProperty(JSON_PROPERTY_TO) String to,
+ @JsonProperty(JSON_PROPERTY_CLIENT_REFERENCE) String clientReference,
+ @JsonProperty(JSON_PROPERTY_OPERATOR_ID) String operatorId,
+ @JsonProperty(JSON_PROPERTY_SENT_AT) OffsetDateTime sendAt,
+ @JsonProperty(JSON_PROPERTY_UDH) String udh) {
+ super(body, from, id, receivedAt, to, clientReference, operatorId, sendAt);
+ this.udh = udh;
+ }
+
+ public String getUdh() {
+ return udh;
+ }
+
+ @Override
+ public String toString() {
+ return "IncomingSMSBinary{" + "udh='" + udh + '\'' + "} " + super.toString();
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSText.java b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSText.java
new file mode 100644
index 00000000..46c5eb08
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/IncomingSMSText.java
@@ -0,0 +1,43 @@
+package com.sinch.sdk.domains.sms.models.webhooks;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.OffsetDateTime;
+
+public class IncomingSMSText extends BaseIncomingSMS {
+
+ /**
+ * Text MO class
+ *
+ * @param body The message content Base64 encoded. Max 140 bytes together with udh.
+ * @param from The phone number that sent the message. @see https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628
+ * @param id The ID of this inbound message.
+ * @param receivedAt When the system received the message.
+ * @param to The Sinch phone number or short code to which the message was sent.
+ * @param clientReference If this inbound message is in response to a previously sent message that
+ * contained a client reference, then this field contains that client reference. Utilizing
+ * this feature requires additional setup on your account. Contact your account manager to
+ * enable this feature.
+ * @param operatorId The MCC/MNC of the sender's operator if known.
+ * @param sendAt When the message left the originating device. Only available if provided by
+ * operator.
+ */
+ @JsonCreator
+ public IncomingSMSText(
+ @JsonProperty(JSON_PROPERTY_BODY) String body,
+ @JsonProperty(JSON_PROPERTY_FROM) String from,
+ @JsonProperty(JSON_PROPERTY_ID) String id,
+ @JsonProperty(JSON_PROPERTY_RECEIVED_AT) OffsetDateTime receivedAt,
+ @JsonProperty(JSON_PROPERTY_TO) String to,
+ @JsonProperty(JSON_PROPERTY_CLIENT_REFERENCE) String clientReference,
+ @JsonProperty(JSON_PROPERTY_OPERATOR_ID) String operatorId,
+ @JsonProperty(JSON_PROPERTY_SENT_AT) OffsetDateTime sendAt) {
+ super(body, from, id, receivedAt, to, clientReference, operatorId, sendAt);
+ }
+
+ @Override
+ public String toString() {
+ return "IncomingSMSText{} " + super.toString();
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/package-info.java b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/package-info.java
new file mode 100644
index 00000000..daf15120
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/webhooks/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * SMS WebHooks models
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.sms.models.webhooks;
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/adapters/WebHKooksServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/WebHKooksServiceTest.java
new file mode 100644
index 00000000..cfac690a
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/WebHKooksServiceTest.java
@@ -0,0 +1,57 @@
+package com.sinch.sdk.domains.sms.adapters;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.adelean.inject.resources.junit.jupiter.GivenTextResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.exceptions.ApiMappingException;
+import com.sinch.sdk.domains.sms.models.dto.v1.webhooks.IncomingSMSBinaryDtoTest;
+import com.sinch.sdk.domains.sms.models.dto.v1.webhooks.IncomingSMSTextDtoTest;
+import com.sinch.sdk.domains.sms.models.webhooks.BaseIncomingSMS;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+
+@TestWithResources
+public class WebHKooksServiceTest extends BaseTest {
+
+ @GivenTextResource("/domains/sms/v1/webhooks/IncomingSMSBinary.json")
+ String incomingSMSBinaryJsonString;
+
+ @GivenTextResource("/domains/sms/v1/webhooks/IncomingSMSText.json")
+ String incomingSMSTextJsonString;
+
+ @InjectMocks WebHooksService service;
+
+ @Test
+ void incomingSMSBinary() throws ApiException {
+
+ BaseIncomingSMS> response = service.incomingSMS(incomingSMSBinaryJsonString);
+
+ Assertions.assertThat(response)
+ .usingRecursiveComparison()
+ .isEqualTo(IncomingSMSBinaryDtoTest.incomingSMSBinary);
+ }
+
+ @Test
+ void incomingSMSText() throws ApiException {
+
+ BaseIncomingSMS> response = service.incomingSMS(incomingSMSTextJsonString);
+
+ Assertions.assertThat(response)
+ .usingRecursiveComparison()
+ .isEqualTo(IncomingSMSTextDtoTest.incomingSMSText);
+ }
+
+ @Test
+ void handleException() throws ApiException {
+
+ String jsonPayload = incomingSMSBinaryJsonString.replace("mo_binary", "foo type");
+ ApiMappingException thrown =
+ assertThrows(ApiMappingException.class, () -> service.incomingSMS(jsonPayload));
+ assertTrue(thrown.getMessage().contains(jsonPayload));
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java b/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java
index d7b31989..883fb3fa 100644
--- a/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java
+++ b/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java
@@ -15,6 +15,10 @@ public ApiException(String message) {
super(message);
}
+ public ApiException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+
public ApiException(String message, Throwable throwable, int code) {
super(message, throwable);
this.code = code;
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/ApiMappingException.java b/core/src/main/com/sinch/sdk/core/exceptions/ApiMappingException.java
new file mode 100644
index 00000000..426aedcd
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/exceptions/ApiMappingException.java
@@ -0,0 +1,8 @@
+package com.sinch.sdk.core.exceptions;
+
+public class ApiMappingException extends ApiException {
+
+ public ApiMappingException(String payload, Throwable throwable) {
+ super(String.format("Unable to map string '%s'", payload), throwable);
+ }
+}
diff --git a/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSBinaryDtoTest.java b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSBinaryDtoTest.java
new file mode 100644
index 00000000..c4427793
--- /dev/null
+++ b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSBinaryDtoTest.java
@@ -0,0 +1,34 @@
+package com.sinch.sdk.domains.sms.models.dto.v1.webhooks;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.domains.sms.models.webhooks.IncomingSMSBinary;
+import java.time.OffsetDateTime;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@TestWithResources
+public class IncomingSMSBinaryDtoTest extends BaseTest {
+
+ @GivenJsonResource("/domains/sms/v1/webhooks/IncomingSMSBinary.json")
+ IncomingSMSBinary client;
+
+ public static IncomingSMSBinary incomingSMSBinary =
+ new IncomingSMSBinary(
+ "VGV4dCBtZXNzYWdl",
+ "16051234567",
+ "01XXXXX21XXXXX119Z8P1XXXXX",
+ OffsetDateTime.parse("2022-08-24T14:15:22Z"),
+ "13185551234",
+ null,
+ "operator",
+ OffsetDateTime.parse("2022-08-24T14:15:44Z"),
+ "10010203040506070809000a0b0c0d0e0f");
+
+ @Test
+ void deserialize() {
+
+ Assertions.assertThat(incomingSMSBinary).usingRecursiveComparison().isEqualTo(client);
+ }
+}
diff --git a/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSTextDtoTest.java b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSTextDtoTest.java
new file mode 100644
index 00000000..c049199b
--- /dev/null
+++ b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/dto/v1/webhooks/IncomingSMSTextDtoTest.java
@@ -0,0 +1,33 @@
+package com.sinch.sdk.domains.sms.models.dto.v1.webhooks;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.domains.sms.models.webhooks.IncomingSMSText;
+import java.time.OffsetDateTime;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@TestWithResources
+public class IncomingSMSTextDtoTest extends BaseTest {
+
+ @GivenJsonResource("/domains/sms/v1/webhooks/IncomingSMSText.json")
+ IncomingSMSText client;
+
+ public static IncomingSMSText incomingSMSText =
+ new IncomingSMSText(
+ "This is a test message.",
+ "16051234567",
+ "01XXXXX21XXXXX119Z8P1XXXXX",
+ OffsetDateTime.parse("2022-08-24T14:15:22Z"),
+ "13185551234",
+ null,
+ "string",
+ null);
+
+ @Test
+ void deserialize() {
+
+ Assertions.assertThat(incomingSMSText).usingRecursiveComparison().isEqualTo(client);
+ }
+}
diff --git a/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSBinary.json b/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSBinary.json
new file mode 100644
index 00000000..2c698b57
--- /dev/null
+++ b/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSBinary.json
@@ -0,0 +1,11 @@
+{
+ "body": "VGV4dCBtZXNzYWdl",
+ "from": "16051234567",
+ "id": "01XXXXX21XXXXX119Z8P1XXXXX",
+ "operator_id": "operator",
+ "received_at": "2022-08-24T14:15:22Z",
+ "sent_at": "2022-08-24T14:15:44Z",
+ "to": "13185551234",
+ "type": "mo_binary",
+ "udh": "10010203040506070809000a0b0c0d0e0f"
+}
\ No newline at end of file
diff --git a/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSText.json b/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSText.json
new file mode 100644
index 00000000..a97b50f0
--- /dev/null
+++ b/test-resources/src/test/resources/domains/sms/v1/webhooks/IncomingSMSText.json
@@ -0,0 +1,9 @@
+{
+ "body": "This is a test message.",
+ "from": "16051234567",
+ "id": "01XXXXX21XXXXX119Z8P1XXXXX",
+ "operator_id": "string",
+ "received_at": "2022-08-24T14:15:22Z",
+ "to": "13185551234",
+ "type": "mo_text"
+}
\ No newline at end of file