clazz) throws UnauthorizedException, GeneralException, NotFoundException {
+ return getJsonData(request, payload, requestType, new HashMap<>(), clazz);
+ }
+
+ public List getJsonDataAsList(final String request, final P payload, final String requestType, final Class elementClass) throws UnauthorizedException, GeneralException, NotFoundException {
+ return getJsonDataAsList(request, payload, requestType, new HashMap<>(), elementClass);
+ }
+
+ public T getJsonData(final String request, final P payload, final String requestType, final Map headers, final Class clazz) throws UnauthorizedException, GeneralException, NotFoundException {
if (request == null) {
throw new IllegalArgumentException(REQUEST_VALUE_MUST_BE_SPECIFIED);
}
@@ -174,26 +260,84 @@ public T getJsonData(final String request, final P payload, final String
if (!isURLAbsolute(url)) {
url = serviceUrl + url;
}
-
- final APIResponse apiResponse = doRequest(requestType, url, payload);
+ final APIResponse apiResponse = doRequest(requestType, url, headers, payload);
final String body = apiResponse.getBody();
final int status = apiResponse.getStatus();
- if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_CREATED) {
- final ObjectMapper mapper = new ObjectMapper();
+ if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_CREATED || status == HttpURLConnection.HTTP_ACCEPTED) {
+ try {
+ final ObjectMapper mapper = new ObjectMapper();
+ // If we as new properties, we don't want the system to fail, we rather want to ignore them
+ mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ // Enable case insensitivity to avoid parsing errors if parameters' case in api response doesn't match sdk's
+ mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
+ mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
+
+ // Prevents mismatched exception when clazz is null
+ return clazz == null
+ ? null
+ : this.readValue(mapper, body, clazz);
+ } catch (IOException ioe) {
+ throw new GeneralException(ioe);
+ }
+ } else if (status == HttpURLConnection.HTTP_NO_CONTENT) {
+ return null; // no content doesn't mean an error
+ }
+ handleHttpFailStatuses(status, body);
+ return null;
+ }
+
+ // todo: need to refactor for duplicated code.
+ public List getJsonDataAsList(final String request,
+ final P payload, final String requestType, final Map headers, final Class elementClass)
+ throws UnauthorizedException, GeneralException, NotFoundException {
+ if (request == null) {
+ throw new IllegalArgumentException(REQUEST_VALUE_MUST_BE_SPECIFIED);
+ }
- // If we as new properties, we don't want the system to fail, we rather want to ignore them
- mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ String url = request;
+ if (!isURLAbsolute(url)) {
+ url = serviceUrl + url;
+ }
+ final APIResponse apiResponse = doRequest(requestType, url, headers, payload);
+ final String body = apiResponse.getBody();
+ final int status = apiResponse.getStatus();
+
+ if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_CREATED || status == HttpURLConnection.HTTP_ACCEPTED) {
try {
- return mapper.readValue(body, clazz);
+ final ObjectMapper mapper = new ObjectMapper();
+ // If we as new properties, we don't want the system to fail, we rather want to ignore them
+ mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ // Enable case insensitivity to avoid parsing errors if parameters' case in api response doesn't match sdk's
+ mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
+ mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
+
+ // Prevents mismatched exception when clazz is null
+ return this.readValueAsList(mapper, body, elementClass);
} catch (IOException ioe) {
throw new GeneralException(ioe);
}
} else if (status == HttpURLConnection.HTTP_NO_CONTENT) {
- return null; // no content doesn't mean an error
- } else if (status == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ return Collections.emptyList(); // no content doesn't mean an error
+ }
+ handleHttpFailStatuses(status, body);
+ return Collections.emptyList();
+ }
+
+ private T readValue(ObjectMapper mapper, String content, Class clazz)
+ throws JsonProcessingException {
+ return mapper.readValue(content, clazz);
+ }
+
+ private List readValueAsList(ObjectMapper mapper, String content, final Class elementClass)
+ throws JsonProcessingException {
+ return mapper.readValue(content, mapper.getTypeFactory().constructCollectionType(List.class, elementClass));
+ }
+
+ private void handleHttpFailStatuses(final int status, String body) throws UnauthorizedException, NotFoundException, GeneralException {
+ if (status == HttpURLConnection.HTTP_UNAUTHORIZED) {
final List errorReport = getErrorReportOrNull(body);
throw new UnauthorizedException(NOT_AUTHORISED_MSG, errorReport);
} else if (status >= 400 && status < 500) { // Any code in the 400 range will have a list of error codes attached
@@ -206,17 +350,17 @@ public T getJsonData(final String request, final P payload, final String
throw new GeneralException(FAILED_DATA_RESPONSE_CODE + status, status);
}
}
-
/**
* Actually sends a HTTP request and returns its body and HTTP status code.
*
* @param method HTTP method.
* @param url Absolute URL.
+ * @param headers additional headers to set on the request.
* @param payload Payload to JSON encode for the request body. May be null.
* @param Type of the payload.
* @return APIResponse containing the response's body and status.
*/
-
APIResponse doRequest(final String method, final String url, final P payload) throws GeneralException {
+
APIResponse doRequest(final String method, final String url, final Map headers, final P payload) throws GeneralException {
HttpURLConnection connection = null;
InputStream inputStream = null;
@@ -231,13 +375,16 @@ APIResponse doRequest(final String method, final String url, final P payload
}
try {
- connection = getConnection(url, payload, method);
+ connection = getConnection(url, payload, method, headers);
int status = connection.getResponseCode();
if (APIResponse.isSuccessStatus(status)) {
inputStream = connection.getInputStream();
} else {
inputStream = connection.getErrorStream();
+ if (inputStream == null) {
+ throw new IOException("Server returned HTTP error code " + status + " with no body.");
+ }
}
return new APIResponse(readToEnd(inputStream), status);
@@ -252,6 +399,66 @@
APIResponse doRequest(final String method, final String url, final P payload
}
}
+ /**
+ *
+ * Do get request for file from input url and stores the file in filepath.
+ * @param url Absolute URL.
+ * @param filePath the path where the downloaded file is going to be stored.
+ * @return if it succeed, it returns filepath otherwise null or exception.
+ */
+ private String doGetRequestForFileAndStore(final String url, final String filePath) throws GeneralException, UnauthorizedException, NotFoundException {
+ HttpURLConnection connection = null;
+ InputStream inputStream = null;
+
+ try {
+ connection = getConnection(url, null, METHOD_GET);
+ int status = connection.getResponseCode();
+
+ if (APIResponse.isSuccessStatus(status)) {
+ inputStream = connection.getInputStream();
+ } else {
+ inputStream = connection.getErrorStream();
+ if (inputStream == null) {
+ throw new GeneralException("Error stream was empty");
+ }
+ }
+ if (status == HttpURLConnection.HTTP_OK) {
+ return writeInputStreamToFile(inputStream, filePath);
+ }
+ String body = readToEnd(inputStream);
+ handleHttpFailStatuses(status, body);
+ } catch (IOException ioe) {
+ throw new GeneralException(ioe);
+ } finally {
+ saveClose(inputStream);
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Writes input stream from IO to filepath.
+ * @param inputStream stream that has been collected file input
+ * @param filepath the storage path for the file
+ * @return if it succeed, it returns filepath otherwise null or exception.
+ * @throws IOException
+ */
+ private String writeInputStreamToFile(InputStream inputStream, String filepath) throws IOException {
+ // opens an output stream to save into file
+ FileOutputStream outputStream = new FileOutputStream(filepath);
+
+ int bytesRead = -1;
+ byte[] buffer = new byte[BUFFER_SIZE];
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, bytesRead);
+ }
+
+ outputStream.close();
+ return filepath;
+ }
+
/**
* By default, HttpURLConnection does not support PATCH requests. We can
* however work around this with reflection. Many thanks to okutane on
@@ -302,6 +509,7 @@ private static String[] getAllowedMethods(String[] existingMethods) {
allowedMethods.addAll(Arrays.asList(existingMethods));
allowedMethods.add(METHOD_PATCH);
+ allowedMethods.add(METHOD_PUT);
return allowedMethods.toArray(new String[0]);
}
@@ -339,18 +547,32 @@ private boolean isURLAbsolute(String url) {
* Create a HttpURLConnection connection object
*
* @param serviceUrl URL that needs to be requested
- * @param postData PostDATA, must be not null for requestType is POST
+ * @param body body could not be empty for POST or PUT requests
* @param requestType Request type POST requests without a payload will generate a exception
* @return base class
* @throws IOException io exception
*/
- public
HttpURLConnection getConnection(final String serviceUrl, final P postData, final String requestType) throws IOException {
+ public
HttpURLConnection getConnection(final String serviceUrl, final P body, final String requestType) throws IOException {
+ return getConnection(serviceUrl, body, requestType, new HashMap<>());
+ }
+
+ /**
+ * Create a HttpURLConnection connection object
+ *
+ * @param serviceUrl URL that needs to be requested
+ * @param body body could not be empty for POST or PUT requests
+ * @param requestType Request type POST requests without a payload will generate a exception
+ * @param headers additional headers to set on the request
+ * @return base class
+ * @throws IOException io exception
+ */
+ public
HttpURLConnection getConnection(final String serviceUrl, final P body, final String requestType, final Map headers) throws IOException {
if (requestType == null || !REQUEST_METHODS.contains(requestType)) {
throw new IllegalArgumentException(String.format(REQUEST_METHOD_NOT_ALLOWED, requestType));
}
- if (postData == null && "POST".equals(requestType)) {
- throw new IllegalArgumentException("POST detected without a payload, please supply a payload with a POST request");
+ if (body == null && ("POST".equals(requestType) || "PUT".equals(requestType))) {
+ throw new IllegalArgumentException("Empty body is not allowed for POST or PUT requests");
}
final URL restService = new URL(serviceUrl);
@@ -368,75 +590,74 @@ public HttpURLConnection getConnection(final String serviceUrl, final P post
connection.setRequestProperty("Authorization", "AccessKey " + accessKey);
connection.setRequestProperty("User-agent", userAgentString);
- if ("POST".equals(requestType) || "PATCH".equals(requestType)) {
+ if ("POST".equals(requestType) || "PUT".equals(requestType) || "PATCH".equals(requestType)) {
connection.setRequestMethod(requestType);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
-
// Specifically set the date format for POST requests so scheduled
// messages and other things relying on specific date formats don't
// fail when sending.
DateFormat df = getDateFormat();
mapper.setDateFormat(df);
- final String json = mapper.writeValueAsString(postData);
- connection.getOutputStream().write(json.getBytes(String.valueOf(StandardCharsets.UTF_8)));
+ setAdditionalHeaders(connection, headers);
+
+ byte[] bodyBytes;
+ if (body instanceof byte[]) {
+ bodyBytes = (byte[]) body;
+ } else {
+ final String json = mapper.writeValueAsString(body);
+ bodyBytes = json.getBytes(StandardCharsets.UTF_8);
+ }
+ connection.getOutputStream().write(bodyBytes);
} else if ("DELETE".equals(requestType)) {
// could have just used rquestType as it is
connection.setDoOutput(false);
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Content-Type", "text/plain");
+
+ setAdditionalHeaders(connection, headers);
} else {
connection.setDoOutput(false);
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "text/plain");
+
+ setAdditionalHeaders(connection, headers);
}
return connection;
}
- private DateFormat getDateFormat() {
- double javaVersion = DEFAULT_JAVA_VERSION;
- try {
- javaVersion = getVersion();
- } catch (GeneralException e) {
- // Do nothing: leave the version at its default.
+ private void setAdditionalHeaders(HttpURLConnection connection, Map headers) {
+ for (Map.Entry header : headers.entrySet()) {
+ connection.setRequestProperty(header.getKey(), header.getValue());
}
+ }
- if (javaVersion > 1.6) {
+ private DateFormat getDateFormat() {
+ ComparableVersion java6 = new ComparableVersion("1.6");
+ if (JAVA_VERSION.compareTo(java6) > 0) {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
}
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ");
}
- private double getVersion() throws GeneralException {
- String version = System.getProperty("java.version");
-
- try {
- int pos = version.indexOf('.');
- pos = version.indexOf('.', pos + 1);
-
- return Double.parseDouble(version.substring(0, pos));
- } catch (RuntimeException e) {
- // Thrown if the index is out of bounds, or when we can't parse a
- // double for some reason.
- throw new GeneralException(e);
- }
- }
-
/**
* Get the MessageBird error report data.
*
- * @param body Raw request body.
+ * @param body Raw response body.
* @return Error report, or null if the body can not be deserialized.
*/
private List getErrorReportOrNull(final String body) {
ObjectMapper objectMapper = new ObjectMapper();
-
try {
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
+ if(!jsonNode.has("errors")) {
+ return null;
+ }
+
ErrorReport[] errors = objectMapper.readValue(jsonNode.get("errors").toString(), ErrorReport[].class);
List result = Arrays.asList(errors);
@@ -523,6 +744,17 @@ private void saveClose(final InputStream is) {
}
}
+ /**
+ * Encodes a key/value pair with percent encoding.
+ *
+ * @param key the key name to be used
+ * @param value the value to be assigned to that key
+ * @return String
+ */
+ private String encodeKeyValuePair(String key, Object value) throws UnsupportedEncodingException {
+ return URLEncoder.encode(key, String.valueOf(StandardCharsets.UTF_8)) + "=" + URLEncoder.encode(String.valueOf(value), String.valueOf(StandardCharsets.UTF_8));
+ }
+
/**
* Build a path variable for GET requests
*
@@ -536,7 +768,30 @@ private String getPathVariables(final Map map) {
bpath.append("&");
}
try {
- bpath.append(URLEncoder.encode(param.getKey(), String.valueOf(StandardCharsets.UTF_8))).append("=").append(URLEncoder.encode(String.valueOf(param.getValue()), String.valueOf(StandardCharsets.UTF_8)));
+ // Check to see if the value is a Collection
+ if (param.getValue() instanceof Collection) {
+ // If it is, cast the value as a Collection explicitly
+ // so it can be iterated over. Its values should be
+ // appended to the querystring parameters using the
+ // original key provided (e.g., ?features=sms&features=mms)
+ Collection> col = (Collection>) param.getValue();
+ Iterator> iterator = col.iterator();
+ int count = 0;
+ // While there are still remaining iterables
+ while (iterator.hasNext()) {
+ // Append & if not the first iterable
+ if (count > 0) {
+ bpath.append("&");
+ }
+ // Append the encoded querystring key/value pair.
+ // the value is returned from the next() call
+ bpath.append(encodeKeyValuePair(param.getKey(), iterator.next()));
+ count++;
+ }
+ } else {
+ // If the value is not a collection, create the querystring value directly.
+ bpath.append(encodeKeyValuePair(param.getKey(), param.getValue()));
+ }
} catch (UnsupportedEncodingException exception) {
// Do nothing
}
diff --git a/api/src/main/java/com/messagebird/Request.java b/api/src/main/java/com/messagebird/Request.java
index 41d9283b..46048b0e 100644
--- a/api/src/main/java/com/messagebird/Request.java
+++ b/api/src/main/java/com/messagebird/Request.java
@@ -5,7 +5,10 @@
/**
* Holds request data needed to calculate a signature hash for incoming
* webhooks.
+ *
+ * @deprecated This class is being deprecated together with {@link RequestSigner}
*/
+@Deprecated
public class Request {
private final String timestamp;
@@ -17,11 +20,13 @@ public class Request {
/**
* Constructs a new request instance.
*
- * @param timestamp Timestamp provided in the MessageBird-Request-Timestamp
- * header.
+ * @param timestamp Timestamp provided in the MessageBird-Request-Timestamp
+ * header.
* @param queryParameters Query parameters in abc=foo&def=ghi format.
- * @param data Raw body of this request.
+ * @param data Raw body of this request.
+ * @deprecated
*/
+ @Deprecated
public Request(String timestamp, String queryParameters, byte[] data) {
if (timestamp == null || timestamp.isEmpty()) {
throw new IllegalArgumentException("Timestamp can not be null or empty");
diff --git a/api/src/main/java/com/messagebird/RequestSigner.java b/api/src/main/java/com/messagebird/RequestSigner.java
index e2f91d93..d79e464c 100644
--- a/api/src/main/java/com/messagebird/RequestSigner.java
+++ b/api/src/main/java/com/messagebird/RequestSigner.java
@@ -4,26 +4,30 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
+import java.util.Base64;
/**
* RequestSigner is used to verify HTTP requests and is an implementation of:
* https://developers.messagebird.com/docs/verify-http-requests. Retrieve your
* signing key at https://dashboard.messagebird.com/developers/settings.
+ *
+ * @deprecated This class is being deprecated.
+ * Use {@link RequestValidator} instead.
*/
+@Deprecated
public class RequestSigner {
private static final String ALGORITHM_SHA256 = "SHA-256";
private static final String ALGORITHM_HMAC_SHA256 = "HmacSHA256";
private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;
- private SecretKeySpec secret;
+ private final SecretKeySpec secret;
/**
* Constructs a new RequestSigner instance.
@@ -31,7 +35,9 @@ public class RequestSigner {
* @param key Signing key. Can be retrieved through
* https://dashboard.messagebird.com/developers/settings. This
* is NOT your API key.
+ * @deprecated Use {@link RequestValidator#RequestValidator(String)} )} instead.
*/
+ @Deprecated
public RequestSigner(byte[] key) {
this.secret = new SecretKeySpec(key, ALGORITHM_HMAC_SHA256);
}
@@ -42,13 +48,15 @@ public RequestSigner(byte[] key) {
*
* @param expectedSignature Signature from the MessageBird-Signature
* header in its original base64 encoded state.
- * @param request Request containing the values from the incoming webhook.
+ * @param request Request containing the values from the incoming webhook.
* @return True if the computed signature matches the expected signature.
+ * @deprecated Use {@link RequestValidator#validateSignature(String, String, byte[])} instead.
*/
+ @Deprecated
public boolean isMatch(String expectedSignature, Request request) {
try {
- return isMatch(Base64.decode(expectedSignature), request);
- } catch (IOException e) {
+ return isMatch(Base64.getDecoder().decode(expectedSignature), request);
+ } catch (IllegalArgumentException e) {
throw new RequestSigningException(e);
}
}
@@ -59,9 +67,11 @@ public boolean isMatch(String expectedSignature, Request request) {
*
* @param expectedSignature Decoded (with base64) signature
* from the MessageBird-Signature header
- * @param request Request containing the values from the incoming webhook.
+ * @param request Request containing the values from the incoming webhook.
* @return True if the computed signature matches the expected signature.
+ * @deprecated Use {@link RequestValidator#validateSignature(String, String, byte[])} instead.
*/
+ @Deprecated
public boolean isMatch(byte[] expectedSignature, Request request) {
return Arrays.equals(computeSignature(request), expectedSignature);
}
@@ -93,7 +103,7 @@ private byte[] getSha256Hash(byte[] bytes) {
/**
* Stitches the two arrays together and returns a new one.
*
- * @param first Start of the new array.
+ * @param first Start of the new array.
* @param second End of the new array.
* @return New array based on first and second.
*/
diff --git a/api/src/main/java/com/messagebird/RequestValidator.java b/api/src/main/java/com/messagebird/RequestValidator.java
new file mode 100644
index 00000000..24ae6343
--- /dev/null
+++ b/api/src/main/java/com/messagebird/RequestValidator.java
@@ -0,0 +1,204 @@
+package com.messagebird;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier.BaseVerification;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.exceptions.SignatureVerificationException;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import com.messagebird.exceptions.RequestValidationException;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.time.Clock;
+
+/**
+ * RequestValidator validates request signature signed by MessageBird services.
+ *
+ * @see Verify HTTP Requests
+ */
+public class RequestValidator {
+
+ /**
+ * Signature of signed request is set with header name 'MessageBird-Signature-JWT'
+ */
+ public static final String SIGNATURE_HEADER = "MessageBird-Signature-JWT";
+ private static final String ALGORITHM_SHA256 = "SHA-256";
+ private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
+ 'e', 'f'};
+
+ private final Algorithm HMAC256, HMAC384, HMAC512;
+
+ /**
+ * This field instructs Validator to not validate url_hash claim.
+ * It is recommended to not skip URL validation to ensure high security.
+ * but the ability to skip URL validation is necessary in some cases, e.g.
+ * your service is behind proxy or when you want to validate it yourself.
+ * Note that when true, no query parameters should be trusted.
+ * Defaults to false.
+ */
+ private final boolean skipURLValidation;
+
+ /**
+ * RequestValidator validates request signature with a customer signature key.
+ *
+ * @param signatureKey customer signature key. Can be retrieved through
+ * Developer Settings.
+ * This is NOT your API key.
+ * @see Verify HTTP Requests
+ */
+ public RequestValidator(String signatureKey) {
+ this(signatureKey, false);
+ }
+
+ /**
+ * RequestValidator validates webhook signature with a customer signature key.
+ *
+ * @param signatureKey customer signature key. Can be retrieved through
+ * Developer Settings.
+ * This is NOT your API key.
+ * @param skipURLValidation whether url_hash claim validation should be skipped.
+ * Note that when true, no query parameters should be trusted.
+ * @see Verify HTTP Requests
+ */
+ public RequestValidator(String signatureKey, boolean skipURLValidation) {
+ this.HMAC256 = Algorithm.HMAC256(signatureKey);
+ this.HMAC384 = Algorithm.HMAC384(signatureKey);
+ this.HMAC512 = Algorithm.HMAC512(signatureKey);
+ this.skipURLValidation = skipURLValidation;
+ }
+
+ /**
+ * Returns raw signature payload after validating a signature successfully,
+ * otherwise throws {@code RequestValidationException}.
+ *
+ * This JWT is signed with a MessageBird account unique secret key, ensuring the request is from MessageBird and
+ * a specific account.
+ * The JWT contains the following claims:
+ *
+ *
+ * - "url_hash" - the raw URL hashed with SHA256 ensuring the URL wasn't altered.
+ * - "payload_hash" - the raw payload hashed with SHA256 ensuring the payload wasn't altered.
+ * - "jti" - a unique token ID to implement an optional non-replay check (NOT validated by default).
+ * - "nbf" - the not before timestamp.
+ * - "exp" - the expiration timestamp is ensuring that a request isn't captured and used at a later time.
+ * - "iss" - the issuer name, always MessageBird.
+ *
+ *
+ * @param clock custom {@link Clock} instance to validate timestamp claims.
+ * @param signature the actual signature.
+ * @param url the raw url including the protocol, hostname and query string,
+ * {@code https://example.com/?example=42}.
+ * @param requestBody the raw request body.
+ * @return raw signature payload as {@link DecodedJWT} object.
+ * @throws RequestValidationException when the signature is invalid.
+ * @see Verify HTTP Requests
+ */
+ public DecodedJWT validateSignature(Clock clock, String signature, String url, byte[] requestBody)
+ throws RequestValidationException {
+ if (signature == null || signature.length() == 0)
+ throw new RequestValidationException("The signature can not be empty.");
+
+ if (!skipURLValidation && (url == null || url.length() == 0))
+ throw new RequestValidationException("The url can not be empty.");
+
+ DecodedJWT jwt = JWT.decode(signature);
+
+ Algorithm algorithm;
+ switch (jwt.getAlgorithm()) {
+ case "HS256":
+ algorithm = HMAC256;
+ break;
+ case "HS384":
+ algorithm = HMAC384;
+ break;
+ case "HS512":
+ algorithm = HMAC512;
+ break;
+ default:
+ throw new RequestValidationException(String.format("The signing method '%s' is invalid.", jwt.getAlgorithm()));
+ }
+
+ BaseVerification builder = (BaseVerification) JWT.require(algorithm)
+ .withIssuer("MessageBird")
+ .ignoreIssuedAt()
+ .acceptLeeway(1);
+
+ if (!skipURLValidation)
+ builder.withClaim("url_hash", calculateSha256(url.getBytes()));
+
+ Claim payloadHashClaim = jwt.getClaim("payload_hash");
+ boolean payloadHashClaimExist = !(payloadHashClaim.isNull() || payloadHashClaim.isMissing());
+ if (requestBody != null && requestBody.length > 0) {
+ if (!payloadHashClaimExist) {
+ throw new RequestValidationException("The Claim 'payload_hash' is not set but payload is present.");
+ }
+ builder.withClaim("payload_hash", calculateSha256(requestBody));
+ } else if (payloadHashClaimExist) {
+ throw new RequestValidationException("The Claim 'payload_hash' is set but actual payload is missing.");
+ }
+
+ JWTVerifier verifier = clock == null ? builder.build() : builder.build(clock);
+
+ try {
+ return verifier.verify(jwt);
+ } catch (SignatureVerificationException e) {
+ throw new RequestValidationException("Signature is invalid.", e);
+ } catch (JWTVerificationException e) {
+ throw new RequestValidationException(e.getMessage(), e.getCause());
+ }
+ }
+
+ /**
+ * Returns raw signature payload after validating a signature successfully,
+ * otherwise throws {@code RequestValidationException}.
+ *
+ * @param signature the actual signature.
+ * @param url the raw url including the protocol, hostname and query string,
+ * {@code https://example.com/?example=42}.
+ * @param requestBody the raw request body.
+ * @return raw signature payload as {@link DecodedJWT} object.
+ * @throws RequestValidationException when the signature is invalid.
+ * @see RequestValidator#validateSignature(Clock, String, String, byte[])
+ */
+ public DecodedJWT validateSignature(String signature, String url, byte[] requestBody)
+ throws RequestValidationException {
+ return validateSignature(null, signature, url, requestBody);
+ }
+
+ /**
+ * Validates request signature with URL validation disabled.
+ * Note that no query parameters should be trusted and this only works if {@code RequestValidator} is constructed
+ * with {@code skipURLValidation} set to true.
+ *
+ * @param signature the actual signature.
+ * @param requestBody the raw request body.
+ * @return raw signature payload as {@link DecodedJWT} object.
+ * @throws RequestValidationException when the signature is invalid.
+ * @see RequestValidator#validateSignature(String, String, byte[])
+ */
+ public DecodedJWT validateSignature(String signature, byte[] requestBody)
+ throws RequestValidationException {
+ return validateSignature(null, signature, null, requestBody);
+ }
+
+ private static String calculateSha256(byte[] bytes) {
+ try {
+ return encodeHex(MessageDigest.getInstance(ALGORITHM_SHA256).digest(bytes));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RequestValidationException(e);
+ }
+ }
+
+ private static String encodeHex(final byte[] data) {
+ final int l = data.length;
+ final char[] out = new char[l << 1];
+ for (int i = 0, j = 0; i < l; i++) {
+ out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
+ out[j++] = HEX_DIGITS[0x0F & data[i]];
+ }
+ return new String(out);
+ }
+}
diff --git a/api/src/main/java/com/messagebird/exceptions/RequestSigningException.java b/api/src/main/java/com/messagebird/exceptions/RequestSigningException.java
index 9f993375..d69a1922 100644
--- a/api/src/main/java/com/messagebird/exceptions/RequestSigningException.java
+++ b/api/src/main/java/com/messagebird/exceptions/RequestSigningException.java
@@ -2,7 +2,10 @@
/**
* Thrown if an error occurs during request signing.
+ *
+ * @deprecated This class is being deprecated together with {@link com.messagebird.RequestSigner}
*/
+@Deprecated
public class RequestSigningException extends RuntimeException {
public RequestSigningException() {
diff --git a/api/src/main/java/com/messagebird/exceptions/RequestValidationException.java b/api/src/main/java/com/messagebird/exceptions/RequestValidationException.java
new file mode 100644
index 00000000..f759b211
--- /dev/null
+++ b/api/src/main/java/com/messagebird/exceptions/RequestValidationException.java
@@ -0,0 +1,22 @@
+package com.messagebird.exceptions;
+
+/**
+ * Thrown if an error occurs during request signing.
+ */
+public class RequestValidationException extends RuntimeException {
+
+ public RequestValidationException() {
+ }
+
+ public RequestValidationException(String message) {
+ super(message);
+ }
+
+ public RequestValidationException(Throwable cause) {
+ super(cause);
+ }
+
+ public RequestValidationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/AccessKey.java b/api/src/main/java/com/messagebird/objects/AccessKey.java
new file mode 100644
index 00000000..4d529711
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/AccessKey.java
@@ -0,0 +1,98 @@
+package com.messagebird.objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class AccessKey {
+ private String id;
+ @JsonProperty("access_key")
+ private String accessKey;
+ private String mode;
+ private String description;
+ @JsonProperty("core_user_id")
+ private int coreUserId;
+ @JsonProperty("user_id")
+ private int userId;
+ @JsonProperty("external_id")
+ private int externalId;
+ private List roles;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAccessKey() {
+ return accessKey;
+ }
+
+ public void setAccessKey(String accessKey) {
+ this.accessKey = accessKey;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getCoreUserId() {
+ return coreUserId;
+ }
+
+ public void setCoreUserId(int coreUserId) {
+ this.coreUserId = coreUserId;
+ }
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public void setUserId(int userId) {
+ this.userId = userId;
+ }
+
+ public int getExternalId() {
+ return externalId;
+ }
+
+ public void setExternalId(int externalId) {
+ this.externalId = externalId;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List roles) {
+ this.roles = roles;
+ }
+
+ @Override
+ public String toString() {
+ return "AccessKey{" +
+ "id='" + id + '\'' +
+ ", access_key='" + accessKey + '\'' +
+ ", mod='" + mode + '\'' +
+ ", description='" + description + '\'' +
+ ", core_user_id=" + coreUserId +
+ ", user_id=" + userId +
+ ", external_id=" + externalId +
+ ", roles=" + roles +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/Balance.java b/api/src/main/java/com/messagebird/objects/Balance.java
index 993bcb6c..ddf653cb 100644
--- a/api/src/main/java/com/messagebird/objects/Balance.java
+++ b/api/src/main/java/com/messagebird/objects/Balance.java
@@ -14,7 +14,7 @@ public class Balance implements Serializable{
private String payment;
private String type;
- private Integer amount;
+ private float amount;
public Balance() {
}
@@ -48,7 +48,7 @@ public String getType() {
* The amount of balance of the payment type. When postpaid is your payment method, the amount will be 0.
* @return
*/
- public Integer getAmount() {
+ public float getAmount() {
return amount;
}
}
diff --git a/api/src/main/java/com/messagebird/objects/ChildAccountCreateResponse.java b/api/src/main/java/com/messagebird/objects/ChildAccountCreateResponse.java
new file mode 100644
index 00000000..40ec38a4
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/ChildAccountCreateResponse.java
@@ -0,0 +1,53 @@
+package com.messagebird.objects;
+
+import java.util.List;
+
+public class ChildAccountCreateResponse extends ChildAccountResponse{
+ private List accessKeys;
+ private String signingKey;
+ private String invoiceAggregation;
+ private String paymentMoment;
+
+ public List getAccessKeys() {
+ return accessKeys;
+ }
+
+ public void setAccessKeys(List accessKeys) {
+ this.accessKeys = accessKeys;
+ }
+
+ public String getSigningKey() {
+ return signingKey;
+ }
+
+ public void setSigningKey(String signingKey) {
+ this.signingKey = signingKey;
+ }
+
+ public String getInvoiceAggregation() {
+ return invoiceAggregation;
+ }
+
+ public void setInvoiceAggregation(String invoiceAggregation) {
+ this.invoiceAggregation = invoiceAggregation;
+ }
+
+ public String getPaymentMoment() {
+ return paymentMoment;
+ }
+
+ public void setPaymentMoment(String paymentMoment) {
+ this.paymentMoment = paymentMoment;
+ }
+
+ @Override
+ public String toString() {
+ return "ChildAccountCreateResponse{" +
+ "id='" + getId() + '\'' +
+ ", name='" + getName() + '\'' +
+ ", accessKeys=" + accessKeys + '\'' +
+ ", invoiceAggregation='" + invoiceAggregation + '\'' +
+ ", paymentMoment='" + paymentMoment + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/ChildAccountDetailedResponse.java b/api/src/main/java/com/messagebird/objects/ChildAccountDetailedResponse.java
new file mode 100644
index 00000000..e39d5969
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/ChildAccountDetailedResponse.java
@@ -0,0 +1,22 @@
+package com.messagebird.objects;
+
+public class ChildAccountDetailedResponse extends ChildAccountResponse{
+ private String invoiceAggregation;
+
+ public String getInvoiceAggregation() {
+ return invoiceAggregation;
+ }
+
+ public void setInvoiceAggregation(String invoiceAggregation) {
+ this.invoiceAggregation = invoiceAggregation;
+ }
+
+ @Override
+ public String toString() {
+ return "ChildAccountDetailedResponse{" +
+ "id='" + getId() + '\'' +
+ ", name='" + getName() + '\'' +
+ ", invoiceAggregation='" + invoiceAggregation + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/ChildAccountRequest.java b/api/src/main/java/com/messagebird/objects/ChildAccountRequest.java
new file mode 100644
index 00000000..aa0e9e5f
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/ChildAccountRequest.java
@@ -0,0 +1,13 @@
+package com.messagebird.objects;
+
+public class ChildAccountRequest {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/ChildAccountResponse.java b/api/src/main/java/com/messagebird/objects/ChildAccountResponse.java
new file mode 100644
index 00000000..de232f05
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/ChildAccountResponse.java
@@ -0,0 +1,34 @@
+package com.messagebird.objects;
+
+import java.io.Serializable;
+
+public class ChildAccountResponse implements Serializable {
+ private static final long serialVersionUID = -8605510461438669942L;
+
+ private String id;
+ private String name;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "ChildAccountResponse{" +
+ "id='" + id + '\'' +
+ ", name='" + name + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/DataCodingType.java b/api/src/main/java/com/messagebird/objects/DataCodingType.java
index 986cea4a..3f78d21d 100644
--- a/api/src/main/java/com/messagebird/objects/DataCodingType.java
+++ b/api/src/main/java/com/messagebird/objects/DataCodingType.java
@@ -7,7 +7,8 @@
*/
public enum DataCodingType {
plain("plain"),
- unicode("unicode");
+ unicode("unicode"),
+ auto("auto");
final String value;
diff --git a/api/src/main/java/com/messagebird/objects/ErrorReport.java b/api/src/main/java/com/messagebird/objects/ErrorReport.java
index 00c74aa9..afd7dcf9 100644
--- a/api/src/main/java/com/messagebird/objects/ErrorReport.java
+++ b/api/src/main/java/com/messagebird/objects/ErrorReport.java
@@ -1,32 +1,46 @@
package com.messagebird.objects;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.io.Serializable;
+
/**
* When MessageBird returns a 4xx, you will find a list of any error codes in your return dataset.
* you will receive a list of errors from the API in such case.
*
* Created by rvt on 1/5/15.
*/
-public class ErrorReport {
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class ErrorReport implements Serializable {
+
+ private static final long serialVersionUID = -8611665867089703268L;
+
private Integer code;
private String description;
private String parameter;
+ private String message;
public ErrorReport() {
}
- public ErrorReport(Integer code, String description, String parameter) {
+ public ErrorReport(Integer code, String description, String parameter, String message) {
this.code = code;
this.description = description;
this.parameter = parameter;
+ this.message = message;
}
@Override
public String toString() {
- return "ErrorReport{" +
- "code=" + code +
- ", description='" + description + '\'' +
- ", parameter='" + parameter + '\'' +
- '}';
+ String str = "ErrorReport{code=" + code;
+ if (message != null && !message.isEmpty()) {
+ str = str.concat(", message='" + message + "'");
+ } else {
+ str = str.concat(", description='" + description + "'");
+ str = str.concat(", parameter='" + parameter + "'");
+ }
+ str = str.concat("}");
+ return str;
}
/**
@@ -53,4 +67,11 @@ public String getParameter() {
return parameter;
}
+ /**
+ * message not null for only voice API response
+ * @return
+ */
+ public String getMessage() {
+ return message;
+ }
}
diff --git a/api/src/main/java/com/messagebird/objects/FileUploadResponse.java b/api/src/main/java/com/messagebird/objects/FileUploadResponse.java
new file mode 100644
index 00000000..29155a63
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/FileUploadResponse.java
@@ -0,0 +1,21 @@
+package com.messagebird.objects;
+
+public class FileUploadResponse {
+
+ private String id;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "FileUploadResponse{" +
+ "id='" + id + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/Language.java b/api/src/main/java/com/messagebird/objects/Language.java
index 6ce76027..ccb63351 100644
--- a/api/src/main/java/com/messagebird/objects/Language.java
+++ b/api/src/main/java/com/messagebird/objects/Language.java
@@ -1,5 +1,7 @@
package com.messagebird.objects;
+import com.fasterxml.jackson.annotation.JsonValue;
+
/**
* Created by faizan on 09/12/15.
*/
@@ -11,7 +13,7 @@ public enum Language {
EN_US("en-us"),
ES_ES("es-es"),
FR_FR("fr-fr"),
- RU_RU("ru_ru"),
+ RU_RU("ru-ru"),
ZH_CN("zh-cn"),
EN_AU("en-au"),
ES_MX("es-mx"),
@@ -25,13 +27,21 @@ public enum Language {
PT_BR("pt-br"),
RO_RO("ro-ro");
- private String code;
+ final String code;
Language(String code) {
this.code = code;
}
+ @JsonValue
+ public String getCode() {
+ return code;
+ }
+
+ @Override
public String toString() {
- return this.code;
+ return "Language{" +
+ "code='" + code + '\'' +
+ '}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/ListBase.java b/api/src/main/java/com/messagebird/objects/ListBase.java
index 354eafa1..da54e709 100644
--- a/api/src/main/java/com/messagebird/objects/ListBase.java
+++ b/api/src/main/java/com/messagebird/objects/ListBase.java
@@ -13,6 +13,7 @@ public class ListBase {
private Integer limit;
private Integer totalCount;
private Links links;
+ private List items;
public ListBase() {
}
@@ -28,7 +29,6 @@ public String toString() {
'}';
}
- private List items;
public Integer getOffset() {
return offset;
diff --git a/api/src/main/java/com/messagebird/objects/MClassType.java b/api/src/main/java/com/messagebird/objects/MClassType.java
index 1f566703..4474b15e 100644
--- a/api/src/main/java/com/messagebird/objects/MClassType.java
+++ b/api/src/main/java/com/messagebird/objects/MClassType.java
@@ -30,7 +30,6 @@ public Integer toJson() {
return getValue();
}
- @JsonCreator
public static MClassType forValue(String value) {
if ("0".equals(value)) {
return flash;
diff --git a/api/src/main/java/com/messagebird/objects/MessageReference.java b/api/src/main/java/com/messagebird/objects/MessageReference.java
index da5fb596..26778292 100644
--- a/api/src/main/java/com/messagebird/objects/MessageReference.java
+++ b/api/src/main/java/com/messagebird/objects/MessageReference.java
@@ -4,6 +4,7 @@ public class MessageReference {
private String href;
private int totalCount;
+ private String lastMessageId;
public String getHREF() {
return href;
@@ -21,11 +22,16 @@ public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
+ public String getLastMessageId() {
+ return lastMessageId;
+ }
+
@Override
public String toString() {
return "MessageReference{" +
"href='" + href + '\'' +
", totalCount=" + totalCount +
+ ", lastMessageId='" + lastMessageId + '\'' +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/MessageResponse.java b/api/src/main/java/com/messagebird/objects/MessageResponse.java
index be132d4f..aa104e52 100644
--- a/api/src/main/java/com/messagebird/objects/MessageResponse.java
+++ b/api/src/main/java/com/messagebird/objects/MessageResponse.java
@@ -1,6 +1,9 @@
package com.messagebird.objects;
+import org.jetbrains.annotations.Nullable;
+
import java.io.Serializable;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
@@ -194,7 +197,7 @@ public Map getTypeDetails() {
static public class Recipients implements Serializable {
private static final long serialVersionUID = 547164972757802213L;
-
+ private Integer totalCount;
private Integer totalSentCount;
private Integer totalDeliveredCount;
private Integer totalDeliveryFailedCount;
@@ -206,13 +209,18 @@ public Recipients() {
@Override
public String toString() {
return "Recipients{" +
- "totalSentCount=" + totalSentCount +
+ "totalCount=" + totalCount +
+ ", totalSentCount=" + totalSentCount +
", totalDeliveredCount=" + totalDeliveredCount +
", totalDeliveryFailedCount=" + totalDeliveryFailedCount +
", items=" + items +
'}';
}
+ public Integer getTotalCount() {
+ return totalCount;
+ }
+
/**
* The count of recipients that have the message pending (status sent, and buffered).
*
@@ -258,8 +266,20 @@ static public class Items implements Serializable {
private static final long serialVersionUID = -4104837036540050532L;
private BigInteger recipient;
+ private BigInteger originator;
private String status;
private Date statusDatetime;
+ private String recipientCountry;
+ private Integer recipientCountryPrefix;
+ private String recipientOperator;
+ private Integer messageLength;
+ private String statusReason;
+ @Nullable
+ private Price price;
+ private String mccmnc;
+ private String mcc;
+ private String mnc;
+ private int messagePartCount;
public Items() {
}
@@ -268,9 +288,20 @@ public Items() {
public String toString() {
return "Items{" +
"recipient=" + recipient +
+ ", originator=" + originator +
", status='" + status + '\'' +
", statusDatetime=" + statusDatetime +
- "}";
+ ", recipientCountry='" + recipientCountry + '\'' +
+ ", recipientCountryPrefix=" + recipientCountryPrefix +
+ ", recipientOperator='" + recipientOperator + '\'' +
+ ", messageLength=" + messageLength +
+ ", statusReason='" + statusReason + '\'' +
+ ", price=" + price +
+ ", mccmnc='" + mccmnc + '\'' +
+ ", mcc='" + mcc + '\'' +
+ ", mnc='" + mnc + '\'' +
+ ", messagePartCount=" + messagePartCount +
+ '}';
}
/**
@@ -300,6 +331,84 @@ public Date getStatusDatetime() {
return statusDatetime;
}
+ public Price getPrice() {
+ return price;
+ }
+
+ public BigInteger getOriginator() {
+ return originator;
+ }
+
+ public String getRecipientCountry() {
+ return recipientCountry;
+ }
+
+ public Integer getRecipientCountryPrefix() {
+ return recipientCountryPrefix;
+ }
+
+ public String getRecipientOperator() {
+ return recipientOperator;
+ }
+
+ public Integer getMessageLength() {
+ return messageLength;
+ }
+
+ public String getStatusReason() {
+ return statusReason;
+ }
+
+ public String getMccmnc() {
+ return mccmnc;
+ }
+
+ public String getMcc() {
+ return mcc;
+ }
+
+ public String getMnc() {
+ return mnc;
+ }
+
+ public int getMessagePartCount() {
+ return messagePartCount;
+ }
+ }
+
+ /**
+ * Response price of items
+ */
+ static public class Price implements Serializable {
+
+ private static final long serialVersionUID = -4104837036540050532L;
+
+ private BigDecimal amount;
+ private String currency;
+
+ public Price() {
+ }
+
+ @Override
+ public String toString() {
+ return "Price{" +
+ "amount=" + amount +
+ ", currency=" + currency +
+ "}";
+ }
+
+ public float getAmount() {
+ return amount.floatValue();
+ }
+
+ public BigDecimal getAmountDecimal() {
+ return amount;
+ }
+
+ public String getCurrency() {
+ return currency;
+ }
+
}
}
diff --git a/api/src/main/java/com/messagebird/objects/MsgType.java b/api/src/main/java/com/messagebird/objects/MsgType.java
index dc9af724..bfc421c8 100644
--- a/api/src/main/java/com/messagebird/objects/MsgType.java
+++ b/api/src/main/java/com/messagebird/objects/MsgType.java
@@ -7,6 +7,7 @@
*/
public enum MsgType {
sms("sms"),
+ mms("mms"),
binary("binary"),
premium("premium"),
flash("flash");
diff --git a/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java b/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java
new file mode 100644
index 00000000..3733cf69
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java
@@ -0,0 +1,60 @@
+package com.messagebird.objects;
+
+import java.math.BigDecimal;
+
+public class OutboundSmsPrice {
+ private BigDecimal price;
+ private String currencyCode;
+ private String mccmnc;
+ private String mcc;
+ private String mnc;
+ private String countryName;
+ private String countryIsoCode;
+ private String operatorName;
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public String getCurrencyCode() {
+ return currencyCode;
+ }
+
+ public String getMccmnc() {
+ return mccmnc;
+ }
+
+ public String getMcc() {
+ return mcc;
+ }
+
+ public String getMnc() {
+ return mnc;
+ }
+
+ public String getCountryName() {
+ return countryName;
+ }
+
+ public String getCountryIsoCode() {
+ return countryIsoCode;
+ }
+
+ public String getOperatorName() {
+ return operatorName;
+ }
+
+ @Override
+ public String toString() {
+ return "OutboundSmsPrice{" +
+ "price=" + price +
+ ", currencyCode='" + currencyCode + '\'' +
+ ", mccmnc='" + mccmnc + '\'' +
+ ", mcc='" + mcc + '\'' +
+ ", mnc='" + mnc + '\'' +
+ ", countryName='" + countryName + '\'' +
+ ", countryIsoCode='" + countryIsoCode + '\'' +
+ ", operatorName='" + operatorName + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java b/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java
new file mode 100644
index 00000000..6d036882
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java
@@ -0,0 +1,36 @@
+package com.messagebird.objects;
+
+import java.util.List;
+
+public class OutboundSmsPriceResponse {
+ private int gateway;
+ private String currencyCode;
+ private int totalCount;
+ private List prices;
+
+ public int getGateway() {
+ return gateway;
+ }
+
+ public String getCurrencyCode() {
+ return currencyCode;
+ }
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public List getPrices() {
+ return prices;
+ }
+
+ @Override
+ public String toString() {
+ return "OutboundSmsPriceResponse{" +
+ "gateway=" + gateway +
+ ", currencyCode='" + currencyCode + '\'' +
+ ", totalCount=" + totalCount +
+ ", prices=" + prices +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumber.java b/api/src/main/java/com/messagebird/objects/PhoneNumber.java
new file mode 100644
index 00000000..5fdda19f
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumber.java
@@ -0,0 +1,50 @@
+package com.messagebird.objects;
+
+import com.messagebird.objects.PhoneNumberFeature;
+
+import java.util.EnumSet;
+
+public class PhoneNumber {
+ private String number;
+ private String country;
+ private String region;
+ private String locality;
+ private EnumSet features;
+ private String type;
+
+ public String getNumber() {
+ return this.number;
+ }
+
+ public String getCountry() {
+ return this.country;
+ }
+
+ public String getRegion() {
+ return this.region;
+ }
+
+ public String getLocality() {
+ return this.locality;
+ }
+
+ public EnumSet getFeatures() {
+ return this.features;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumber{" +
+ "number='" + number + "\'" +
+ ", country='" + country + "\'" +
+ ", region='" + region + "\'" +
+ ", locality='" + locality + "\'" +
+ ", features=" + features +
+ ", type='" + type + "\'" +
+ "}";
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumberFeature.java b/api/src/main/java/com/messagebird/objects/PhoneNumberFeature.java
new file mode 100644
index 00000000..790177c9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumberFeature.java
@@ -0,0 +1,19 @@
+package com.messagebird.objects;
+
+public enum PhoneNumberFeature {
+
+ SMS("sms"),
+ MMS("mms"),
+ VOICE("voice");
+
+ private String type;
+
+ PhoneNumberFeature(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return this.type;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumberSearchPattern.java b/api/src/main/java/com/messagebird/objects/PhoneNumberSearchPattern.java
new file mode 100644
index 00000000..cf0b3099
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumberSearchPattern.java
@@ -0,0 +1,18 @@
+package com.messagebird.objects;
+
+public enum PhoneNumberSearchPattern {
+ START("start"),
+ ANYWHERE("anywhere"),
+ END("end");
+
+ private String type;
+
+ PhoneNumberSearchPattern(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return this.type;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumberType.java b/api/src/main/java/com/messagebird/objects/PhoneNumberType.java
new file mode 100644
index 00000000..82908203
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumberType.java
@@ -0,0 +1,18 @@
+package com.messagebird.objects;
+
+public enum PhoneNumberType {
+ LANDLINE("landline"),
+ MOBILE("mobile"),
+ PREMIUM_RATE("premium_rate");
+
+ private String type;
+
+ PhoneNumberType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return this.type;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumbersLookup.java b/api/src/main/java/com/messagebird/objects/PhoneNumbersLookup.java
new file mode 100644
index 00000000..8b8396fa
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumbersLookup.java
@@ -0,0 +1,93 @@
+package com.messagebird.objects;
+
+import com.messagebird.exceptions.GeneralException;
+import com.messagebird.objects.PhoneNumberFeature;
+import com.messagebird.objects.PhoneNumberType;
+import com.messagebird.objects.PhoneNumberSearchPattern;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.lang.reflect.Field;
+
+public class PhoneNumbersLookup {
+
+ private Number number;
+ private Number limit;
+ private EnumSet features;
+ private PhoneNumberType type;
+ private PhoneNumberSearchPattern searchPattern;
+
+ public Number getNumber() {
+ return this.number;
+ }
+
+ public EnumSet getFeatures() {
+ return this.features;
+ }
+
+ public PhoneNumberType getType() {
+ return this.type;
+ }
+
+ public Number getLimit() {
+ return this.limit;
+ }
+
+ public PhoneNumberSearchPattern getSearchPattern() {
+ return this.searchPattern;
+ }
+
+ public void setNumber(Number number) {
+ this.number = number;
+ }
+
+ public void setFeatures(EnumSet features) {
+ this.features = features;
+ }
+
+ public void setFeatures(PhoneNumberFeature... features) {
+ EnumSet featuresEnum = EnumSet.noneOf(PhoneNumberFeature.class);
+ featuresEnum.addAll(Arrays.asList(features));
+ this.features = featuresEnum;
+ }
+
+ public void setType(PhoneNumberType type) {
+ this.type = type;
+ }
+
+ public void setLimit(Number limit) {
+ this.limit = limit;
+ }
+
+ public void setSearchPattern(PhoneNumberSearchPattern searchPattern) {
+ this.searchPattern = searchPattern;
+ }
+
+ public HashMap toHashMap() throws GeneralException {
+ final HashMap map = new HashMap();
+ for (Field f: getClass().getDeclaredFields()) {
+ try {
+ Object value = f.get(this);
+ String key = f.getName();
+ if (value != null) {
+ map.put(key, value);
+ }
+ } catch (IllegalAccessException exception) {
+ throw new GeneralException("Error Converting PhoneNumbersLookup Class to HashMap.");
+ }
+ }
+ return map;
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumbersLookup{" +
+ " number='" + number + "'" +
+ ", features='" + features + "'" +
+ ", type='" + type + "'" +
+ ", limit='" + limit + "'" +
+ ", searchPattern='" + searchPattern + "'" +
+ "}";
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/PhoneNumbersResponse.java b/api/src/main/java/com/messagebird/objects/PhoneNumbersResponse.java
new file mode 100644
index 00000000..68e9ef4d
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PhoneNumbersResponse.java
@@ -0,0 +1,38 @@
+package com.messagebird.objects;
+
+import com.messagebird.objects.PhoneNumber;
+
+import java.util.List;
+
+import java.io.Serializable;
+
+public class PhoneNumbersResponse implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6177098534499444839L;
+ private Number limit;
+ private Number offset;
+ private List items;
+
+ public Number getLimit() {
+ return this.limit;
+ }
+
+ public Number getOffset() {
+ return this.offset;
+ }
+
+ public List getItems() {
+ return this.items;
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumbersResponse{" +
+ "limit=" + limit +
+ ", offset=" + offset +
+ ", items=" + items +
+ "}";
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/PurchasedNumber.java b/api/src/main/java/com/messagebird/objects/PurchasedNumber.java
new file mode 100644
index 00000000..fb07a686
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PurchasedNumber.java
@@ -0,0 +1,30 @@
+package com.messagebird.objects;
+
+import java.util.List;
+
+public class PurchasedNumber extends PhoneNumber {
+ private List tags;
+ private String status;
+
+ public List getTags() {
+ return tags;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumber{" +
+ "number='" + this.getNumber() + "\'" +
+ ", country='" + this.getCountry() + "\'" +
+ ", region='" + this.getRegion() + "\'" +
+ ", locality='" + this.getLocality() + "\'" +
+ ", features=" + this.getFeatures() +
+ ", type='" + this.getType() + "\'" +
+ ", tags='" + tags + "\'" +
+ ", status='" + status + "\'" +
+ "}";
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/PurchasedNumberCreatedResponse.java b/api/src/main/java/com/messagebird/objects/PurchasedNumberCreatedResponse.java
new file mode 100644
index 00000000..8922db2e
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PurchasedNumberCreatedResponse.java
@@ -0,0 +1,32 @@
+package com.messagebird.objects;
+
+import java.util.Date;
+
+public class PurchasedNumberCreatedResponse extends PurchasedNumber {
+ private Date createdAt;
+ private Date renewalAt;
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public Date getRenewalAt() {
+ return renewalAt;
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumber{" +
+ "number='" + this.getNumber() + "\'" +
+ ", country='" + this.getCountry() + "\'" +
+ ", region='" + this.getRegion() + "\'" +
+ ", locality='" + this.getLocality() + "\'" +
+ ", features=" + this.getFeatures() +
+ ", type='" + this.getType() + "\'" +
+ ", tags='" + this.getTags() + "\'" +
+ ", status='" + this.getStatus() + "\'" +
+ ", createdAt='" + createdAt + "\'" +
+ ", renewalAt='" + renewalAt + "\'" +
+ "}";
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/PurchasedNumbersFilter.java b/api/src/main/java/com/messagebird/objects/PurchasedNumbersFilter.java
new file mode 100644
index 00000000..40c6dcd9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PurchasedNumbersFilter.java
@@ -0,0 +1,135 @@
+package com.messagebird.objects;
+
+import com.messagebird.exceptions.GeneralException;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+
+public class PurchasedNumbersFilter implements Serializable {
+ private int limit = 10;
+ private int offset = 0;
+ private EnumSet features = EnumSet.noneOf(PhoneNumberFeature.class);
+ private ArrayList tags = new ArrayList<>();
+ private String number;
+ private String region;
+ private String locality;
+ private PhoneNumberType type;
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ public EnumSet getFeatures() {
+ return features;
+ }
+
+ public void addFeature(PhoneNumberFeature... features) {
+ Collections.addAll(this.features, features);
+ }
+
+ public void removeFeature(PhoneNumberFeature... features) {
+ for (PhoneNumberFeature feature: features) {
+ this.features.remove(feature);
+ }
+ }
+
+ public ArrayList getTags() {
+ return tags;
+ }
+
+ public void addTag(String... tags) {
+ for (String tag: tags) {
+ if (!this.tags.contains(tag)) {
+ this.tags.add(tag);
+ }
+ }
+ }
+
+ public void removeTag(String... tags) {
+ for (String tag: tags) {
+ this.tags.remove(tag);
+ }
+ }
+
+ public void clearTags() {
+ this.tags.clear();
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ public void setNumber(String number) {
+ this.number = number;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+
+ public String getLocality() {
+ return locality;
+ }
+
+ public void setLocality(String locality) {
+ this.locality = locality;
+ }
+
+ public PhoneNumberType getType() {
+ return type;
+ }
+
+ public void setType(PhoneNumberType type) {
+ this.type = type;
+ }
+
+ public HashMap toHashMap() throws GeneralException {
+ final HashMap map = new HashMap();
+ for (Field f: getClass().getDeclaredFields()) {
+ try {
+ Object value = f.get(this);
+ String key = f.getName();
+ if (value != null) {
+ map.put(key, value);
+ }
+ } catch (IllegalAccessException exception) {
+ throw new GeneralException("Error converting to HashMap.");
+ }
+ }
+ return map;
+ }
+
+ @Override
+ public String toString() {
+ return "PurchasedNumbersFilter{" +
+ "limit=" + limit +
+ ", offset=" + offset +
+ ", features=" + features +
+ ", tags=" + tags +
+ ", number='" + number + '\'' +
+ ", region='" + region + '\'' +
+ ", locality='" + locality + '\'' +
+ ", type=" + type +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/PurchasedNumbersResponse.java b/api/src/main/java/com/messagebird/objects/PurchasedNumbersResponse.java
new file mode 100644
index 00000000..b61928ca
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/PurchasedNumbersResponse.java
@@ -0,0 +1,42 @@
+package com.messagebird.objects;
+
+import java.util.List;
+
+public class PurchasedNumbersResponse {
+ private int offset;
+ private int limit;
+ private int count;
+ private int totalCount;
+ private List items;
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ @Override
+ public String toString() {
+ return "PurchasedNumbersResponse{" +
+ "offset=" + offset +
+ ", limit=" + limit +
+ ", count=" + count +
+ ", totalCount=" + totalCount +
+ ", items=" + items +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/VerifyMessage.java b/api/src/main/java/com/messagebird/objects/VerifyMessage.java
new file mode 100644
index 00000000..b2929f11
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/VerifyMessage.java
@@ -0,0 +1,35 @@
+package com.messagebird.objects;
+
+import java.io.Serializable;
+
+/**
+ * Created by leandro.pinto on 22/06/15.
+ */
+public class VerifyMessage implements Serializable {
+
+ private String id;
+ private String status;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String toString() {
+ return "VerifyMessage {" + " " +
+ "id=" + this.id + " " +
+ "status=" + this.status + " " +
+ "}";
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/VerifyRequest.java b/api/src/main/java/com/messagebird/objects/VerifyRequest.java
index 45a6b194..bee684e9 100644
--- a/api/src/main/java/com/messagebird/objects/VerifyRequest.java
+++ b/api/src/main/java/com/messagebird/objects/VerifyRequest.java
@@ -15,8 +15,10 @@ public class VerifyRequest implements Serializable {
private String template;
private Integer timeout;
private Integer tokenLength;
+ private Integer maxAttempts;
private Gender voice;
private Language language;
+ private String subject;
public VerifyRequest(String recipient) {
this.recipient = recipient;
@@ -54,6 +56,10 @@ public void setType(VerifyType type) {
this.type = type;
}
+ public void setType(String type) {
+ this.type = VerifyType.valueOf(type.toUpperCase());
+ }
+
/**
* The datacoding used by the template.
*
@@ -112,4 +118,19 @@ public void setLanguage(Language language) {
this.language = language;
}
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public Integer getMaxAttempts() {
+ return maxAttempts;
+ }
+
+ public void setMaxAttempts(Integer maxAttempts) {
+ this.maxAttempts = maxAttempts;
+ }
}
diff --git a/api/src/main/java/com/messagebird/objects/VerifyType.java b/api/src/main/java/com/messagebird/objects/VerifyType.java
index 8965e7a2..630e8e53 100644
--- a/api/src/main/java/com/messagebird/objects/VerifyType.java
+++ b/api/src/main/java/com/messagebird/objects/VerifyType.java
@@ -9,7 +9,8 @@ public enum VerifyType {
FLASH("flash"),
SMS("sms"),
- TTS("tts");
+ TTS("tts"),
+ EMAIL("email");
final String value;
diff --git a/api/src/main/java/com/messagebird/objects/VoiceMessage.java b/api/src/main/java/com/messagebird/objects/VoiceMessage.java
index 8d941051..0674851e 100644
--- a/api/src/main/java/com/messagebird/objects/VoiceMessage.java
+++ b/api/src/main/java/com/messagebird/objects/VoiceMessage.java
@@ -22,6 +22,7 @@ public class VoiceMessage implements MessageBase, Serializable {
private VoiceType voice;
private Integer repeat;
private IfMachineType ifMachine;
+ private int machineTimeout;
private Date scheduledDatetime;
public VoiceMessage(String body, List recipients) {
@@ -171,6 +172,22 @@ public void setIfMachine(IfMachineType ifMachine) {
this.ifMachine = ifMachine;
}
+ /**
+ * The time (in milliseconds) to analyze if a machine has picked up the phone.
+ * Used in combination with the delay and hangup values of the ifMachine attribute.
+ * Minimum: 400, maximum: 10000. Default: 7000
+ * @return value of machine timeout
+ */
+ public int getMachineTimeout() { return machineTimeout; }
+
+ /**
+ * The time (in milliseconds) to analyze if a machine has picked up the phone.
+ * Used in combination with the delay and hangup values of the ifMachine attribute.
+ * Minimum: 400, maximum: 10000. Default: 7000
+ * @param machineTimeout value of machine timeout
+ */
+ public void setMachineTimeout(int machineTimeout) { this.machineTimeout = machineTimeout; }
+
@Override
public Date getScheduledDatetime() {
return scheduledDatetime;
diff --git a/api/src/main/java/com/messagebird/objects/VoiceMessageResponse.java b/api/src/main/java/com/messagebird/objects/VoiceMessageResponse.java
index fe8d56f1..6563919e 100644
--- a/api/src/main/java/com/messagebird/objects/VoiceMessageResponse.java
+++ b/api/src/main/java/com/messagebird/objects/VoiceMessageResponse.java
@@ -21,6 +21,7 @@ public class VoiceMessageResponse implements MessageResponseBase, Serializable {
private VoiceType voice;
private Integer repeat;
private IfMachineType ifMachine;
+ private int machineTimeout;
private Date scheduledDatetime;
private Date createdDatetime;
private MessageResponse.Recipients recipients;
@@ -40,6 +41,7 @@ public String toString() {
", voice=" + voice +
", repeat=" + repeat +
", ifMachine=" + ifMachine +
+ ", machineTimeout=" + machineTimeout +
", scheduledDatetime=" + scheduledDatetime +
", createdDatetime=" + createdDatetime +
", recipients=" + recipients +
@@ -114,6 +116,14 @@ public IfMachineType getIfMachine() {
return ifMachine;
}
+ /**
+ * The time (in milliseconds) to analyze if a machine has picked up the phone.
+ * Used in combination with the delay and hangup values of the ifMachine attribute.
+ * Minimum: 400, maximum: 10000. Default: 7000
+ * @return value of machine timeout
+ */
+ public int getMachineTimeout() { return machineTimeout; }
+
/**
* The scheduled date and time of the message
*
diff --git a/api/src/main/java/com/messagebird/objects/VoiceStep.java b/api/src/main/java/com/messagebird/objects/VoiceStep.java
index 25d56c20..8958f8b8 100644
--- a/api/src/main/java/com/messagebird/objects/VoiceStep.java
+++ b/api/src/main/java/com/messagebird/objects/VoiceStep.java
@@ -1,6 +1,9 @@
package com.messagebird.objects;
+import com.messagebird.objects.voicecalls.VoiceCallCondition;
+
import java.io.Serializable;
+import java.util.Arrays;
public class VoiceStep implements Serializable {
@@ -10,6 +13,11 @@ public class VoiceStep implements Serializable {
private String action;
private VoiceStepOption options;
+ private VoiceCallCondition[] conditions;
+
+ private String onKeypressGoto;
+ private String onKeypressVar;
+
public String getId() {
return id;
}
@@ -34,12 +42,43 @@ public void setOptions(VoiceStepOption options) {
this.options = options;
}
+ public VoiceCallCondition[] getConditions() {
+ return conditions;
+ }
+
+ public void setConditions(VoiceCallCondition[] conditions) {
+ this.conditions = conditions;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public String getOnKeypressGoto() {
+ return onKeypressGoto;
+ }
+
+ public void setOnKeypressGoto(String onKeypressGoto) {
+ this.onKeypressGoto = onKeypressGoto;
+ }
+
+ public String getOnKeypressVar() {
+ return onKeypressVar;
+ }
+
+ public void setOnKeypressVar(String onKeypressVar) {
+ this.onKeypressVar = onKeypressVar;
+ }
+
@Override
public String toString() {
return "VoiceStep{" +
"id='" + id + '\'' +
", action='" + action + '\'' +
", options=" + options +
+ ", conditions=" + Arrays.toString(conditions) +
+ ", onKeypressGoto='" + onKeypressGoto + '\'' +
+ ", onKeypressVar='" + onKeypressVar + '\'' +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/VoiceStepOption.java b/api/src/main/java/com/messagebird/objects/VoiceStepOption.java
index 179513e3..70c0670b 100644
--- a/api/src/main/java/com/messagebird/objects/VoiceStepOption.java
+++ b/api/src/main/java/com/messagebird/objects/VoiceStepOption.java
@@ -10,7 +10,7 @@ public class VoiceStepOption implements Serializable {
private String payload;
private String language;
private String voice;
- private String repeat;
+ private int repeat;
private String media;
private int length;
private int maxLength;
@@ -23,6 +23,10 @@ public class VoiceStepOption implements Serializable {
private String ifMachine;
private int machineTimeout;
private String onFinish;
+ private boolean mask;
+ private String keys;
+ private int duration;
+ private int interval;
public String getDestination() {
return destination;
@@ -56,11 +60,11 @@ public void setVoice(String voice) {
this.voice = voice;
}
- public String getRepeat() {
+ public int getRepeat() {
return repeat;
}
- public void setRepeat(String repeat) {
+ public void setRepeat(int repeat) {
this.repeat = repeat;
}
@@ -160,6 +164,26 @@ public void setOnFinish(String onFinish) {
this.onFinish = onFinish;
}
+ public boolean isMask() {
+ return mask;
+ }
+
+ public void setMask(boolean mask) {
+ this.mask = mask;
+ }
+
+ public String getKeys() { return keys; }
+
+ public void setKeys(String keys) { this.keys = keys; }
+
+ public int getDuration() { return duration; }
+
+ public void setDuration(int duration) { this.duration = duration; }
+
+ public int getInterval() { return interval; }
+
+ public void setInterval(int interval) { this.interval = interval; }
+
@Override
public String toString() {
return "VoiceStepOption{" +
@@ -180,6 +204,10 @@ public String toString() {
", ifMachine='" + ifMachine + '\'' +
", machineTimeout=" + machineTimeout +
", onFinish='" + onFinish + '\'' +
+ ", mask=" + mask + '\'' +
+ ", keys='" + keys + '\'' +
+ ", interval='" + interval + '\'' +
+ ", duration='" + duration +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationChannel.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationChannel.java
index 32db29e6..2c2bd06e 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationChannel.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationChannel.java
@@ -11,6 +11,8 @@ public class ConversationChannel {
private String id;
private String name;
+ // See: ConversationPlatformConstants
+ private String platformId;
private ConversationChannelStatus status;
private Date createdDatetime;
private Date updatedDatetime;
@@ -55,11 +57,20 @@ public void setUpdatedDatetime(final Date updatedDatetime) {
this.updatedDatetime = updatedDatetime;
}
+ public String getPlatformId() {
+ return platformId;
+ }
+
+ public void setPlatformId(String platformId) {
+ this.platformId = platformId;
+ }
+
@Override
public String toString() {
return "ConversationChannel{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
+ ", platformId=" + platformId +
", status=" + status +
", createdDatetime=" + createdDatetime +
", updatedDatetime=" + updatedDatetime +
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java
index 2edfb5b3..8b4fe164 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java
@@ -1,9 +1,16 @@
package com.messagebird.objects.conversations;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
/**
* ConversationContent wraps actual content. The field that should be set here
* is indicated by ConversationContentType.
+ *
+ * Unknown keys are ignored on deserialization so that consumers parsing
+ * webhook payloads in their own handlers are not broken by content fields added
+ * after their SDK version. Serialization is unaffected.
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class ConversationContent {
private ConversationContentMedia audio;
@@ -11,6 +18,7 @@ public class ConversationContent {
private ConversationContentHsm hsm;
private ConversationContentMedia image;
private ConversationContentLocation location;
+ private ConversationContentEmail email;
private String text;
private ConversationContentMedia video;
@@ -70,6 +78,14 @@ public void setVideo(ConversationContentMedia video) {
this.video = video;
}
+ public ConversationContentEmail getEmail() {
+ return email;
+ }
+
+ public void setEmail(ConversationContentEmail email) {
+ this.email = email;
+ }
+
@Override
public String toString() {
return "ConversationContent{" +
@@ -78,6 +94,7 @@ public String toString() {
", hsm=" + hsm +
", image=" + image +
", location=" + location +
+ ", email=" + email +
", text='" + text + '\'' +
", video=" + video +
'}';
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentEmail.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentEmail.java
new file mode 100644
index 00000000..3ba8b2d8
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentEmail.java
@@ -0,0 +1,133 @@
+package com.messagebird.objects.conversations;
+
+import java.util.List;
+import java.util.Map;
+
+public class ConversationContentEmail {
+ private String id;
+ private ConversationEmailRecipient from;
+ private List to;
+ private String subject;
+ private ConversationEmailContent content;
+ private String replyTo;
+ private String returnPath;
+ private Map headers;
+ private ConversationEmailTracking tracking;
+ private boolean performSubstitutions;
+ private List attachments;
+ private List inlineImages;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public ConversationEmailRecipient getFrom() {
+ return from;
+ }
+
+ public void setFrom(ConversationEmailRecipient from) {
+ this.from = from;
+ }
+
+ public List getTo() {
+ return to;
+ }
+
+ public void setTo(List to) {
+ this.to = to;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public ConversationEmailContent getContent() {
+ return content;
+ }
+
+ public void setContent(ConversationEmailContent content) {
+ this.content = content;
+ }
+
+ public String getReplyTo() {
+ return replyTo;
+ }
+
+ public void setReplyTo(String replyTo) {
+ this.replyTo = replyTo;
+ }
+
+ public String getReturnPath() {
+ return returnPath;
+ }
+
+ public void setReturnPath(String returnPath) {
+ this.returnPath = returnPath;
+ }
+
+ public Map getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map headers) {
+ this.headers = headers;
+ }
+
+ public ConversationEmailTracking getTracking() {
+ return tracking;
+ }
+
+ public void setTracking(ConversationEmailTracking tracking) {
+ this.tracking = tracking;
+ }
+
+ public boolean isPerformSubstitutions() {
+ return performSubstitutions;
+ }
+
+ public void setPerformSubstitutions(boolean performSubstitutions) {
+ this.performSubstitutions = performSubstitutions;
+ }
+
+ public List getAttachments() {
+ return attachments;
+ }
+
+ public void setAttachments(List attachments) {
+ this.attachments = attachments;
+ }
+
+ public List getInlineImages() {
+ return inlineImages;
+ }
+
+ public void setInlineImages(List inlineImages) {
+ this.inlineImages = inlineImages;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationContentEmail{" +
+ "id='" + id + '\'' +
+ ", from=" + from +
+ ", to=" + to +
+ ", subject='" + subject + '\'' +
+ ", content=" + content +
+ ", replyTo='" + replyTo + '\'' +
+ ", returnPath='" + returnPath + '\'' +
+ ", headers=" + headers +
+ ", tracking=" + tracking +
+ ", performSubstitutions=" + performSubstitutions +
+ ", attachments=" + attachments +
+ ", inlineImages=" + inlineImages +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentHsm.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentHsm.java
index 3da74c2c..824f7fc8 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentHsm.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentHsm.java
@@ -18,17 +18,20 @@ public class ConversationContentHsm {
private String templateName;
private ConversationHsmLanguage language;
private List params;
+ private List components;
public ConversationContentHsm(
final String namespace,
final String templateName,
final ConversationHsmLanguage language,
- final List params
+ final List params,
+ final List components
) {
this.namespace = namespace;
this.templateName = templateName;
this.language = language;
this.params = params;
+ this.components = components;
}
public ConversationContentHsm(
@@ -85,6 +88,14 @@ public void setParams(final List params) {
this.params = params;
}
+ public List getComponents() {
+ return components;
+ }
+
+ public void setComponents(List components) {
+ this.components = components;
+ }
+
@Override
public String toString() {
return "ConversationContentHsm{" +
@@ -92,6 +103,7 @@ public String toString() {
", templateName='" + templateName + '\'' +
", language=" + language +
", params=" + params +
+ ", components=" + components +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentMedia.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentMedia.java
index b2d1e4ca..7ac29e8f 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentMedia.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentMedia.java
@@ -7,6 +7,12 @@
public class ConversationContentMedia {
private String url;
+ private String caption;
+
+ public ConversationContentMedia(final String url, final String caption) {
+ this.url = url;
+ this.caption = caption;
+ }
public ConversationContentMedia(final String url) {
this.url = url;
@@ -24,10 +30,19 @@ public void setUrl(final String url) {
this.url = url;
}
+ public String getCaption() {
+ return caption;
+ }
+
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
@Override
public String toString() {
return "ConversationContentMedia{" +
"url='" + url + '\'' +
+ ", caption='" + caption + '\'' +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentType.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentType.java
index 93f6bb4f..3dec398a 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationContentType.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContentType.java
@@ -15,7 +15,8 @@ public enum ConversationContentType {
IMAGE("image"),
LOCATION("location"),
TEXT("text"),
- VIDEO("video");
+ VIDEO("video"),
+ EMAIL("email");
private final String type;
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailAttachment.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailAttachment.java
new file mode 100644
index 00000000..82e1a48a
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailAttachment.java
@@ -0,0 +1,60 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationEmailAttachment {
+ private String id;
+ private String name;
+ private String type;
+ private String URL;
+ private String length;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getURL() {
+ return URL;
+ }
+
+ public void setURL(String URL) {
+ this.URL = URL;
+ }
+
+ public String getLength() {
+ return length;
+ }
+
+ public void setLength(String length) {
+ this.length = length;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationEmailAttachment{" +
+ "id='" + id + '\'' +
+ ", name='" + name + '\'' +
+ ", type='" + type + '\'' +
+ ", URL='" + URL + '\'' +
+ ", length='" + length + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailContent.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailContent.java
new file mode 100644
index 00000000..7127b104
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailContent.java
@@ -0,0 +1,30 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationEmailContent {
+ private String html;
+ private String text;
+
+ public String getHtml() {
+ return html;
+ }
+
+ public void setHtml(String html) {
+ this.html = html;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationEmailContent{" +
+ "html='" + html + '\'' +
+ ", text='" + text + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailInlineImage.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailInlineImage.java
new file mode 100644
index 00000000..a7318216
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailInlineImage.java
@@ -0,0 +1,70 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationEmailInlineImage {
+ private String id;
+ private String name;
+ private String type;
+ private String URL;
+ private int length;
+ private String contentId;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getURL() {
+ return URL;
+ }
+
+ public void setURL(String URL) {
+ this.URL = URL;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ public String getContentId() {
+ return contentId;
+ }
+
+ public void setContentId(String contentId) {
+ this.contentId = contentId;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationEmailInlineImage{" +
+ "id='" + id + '\'' +
+ ", name='" + name + '\'' +
+ ", type='" + type + '\'' +
+ ", URL='" + URL + '\'' +
+ ", length=" + length +
+ ", contentId='" + contentId + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailRecipient.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailRecipient.java
new file mode 100644
index 00000000..f5bbdfb9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailRecipient.java
@@ -0,0 +1,42 @@
+package com.messagebird.objects.conversations;
+
+import java.util.Map;
+
+public class ConversationEmailRecipient {
+ private String address;
+ private String name;
+ private Map variables;
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map getVariables() {
+ return variables;
+ }
+
+ public void setVariables(Map variables) {
+ this.variables = variables;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationEmailRecipient{" +
+ "address='" + address + '\'' +
+ ", name='" + name + '\'' +
+ ", variables=" + variables +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailTracking.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailTracking.java
new file mode 100644
index 00000000..b8861d14
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationEmailTracking.java
@@ -0,0 +1,30 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationEmailTracking {
+ private boolean open;
+ private boolean click;
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ public void setOpen(boolean open) {
+ this.open = open;
+ }
+
+ public boolean isClick() {
+ return click;
+ }
+
+ public void setClick(boolean click) {
+ this.click = click;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationEmailTracking{" +
+ "open=" + open +
+ ", click=" + click +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationFallbackOption.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationFallbackOption.java
new file mode 100644
index 00000000..0048de12
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationFallbackOption.java
@@ -0,0 +1,38 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationFallbackOption {
+ private String from;
+ private String after;
+
+ public ConversationFallbackOption() {
+ }
+
+ public ConversationFallbackOption(String from, String after) {
+ this.from = from;
+ this.after = after;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getAfter() {
+ return after;
+ }
+
+ public void setAfter(String after) {
+ this.after = after;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationFallbackOption{" +
+ "from='" + from + '\'' +
+ ", after='" + after + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationHsmLocalizableParameterCurrency.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationHsmLocalizableParameterCurrency.java
index b17ecbce..708938ee 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationHsmLocalizableParameterCurrency.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationHsmLocalizableParameterCurrency.java
@@ -11,10 +11,10 @@ public class ConversationHsmLocalizableParameterCurrency {
/**
* Instantiates a localizable parameter for currencies.
*
- * @param code ISO 4217 compliant currency code.
+ * @param currencyCode ISO 4217 compliant currency code.
* @param amount Amount multiplied by 1000. E.g. 12.34 becomes 12340.
*/
- public ConversationHsmLocalizableParameterCurrency(final String code, final int amount) {
+ public ConversationHsmLocalizableParameterCurrency(final String currencyCode, final int amount) {
this.currencyCode = currencyCode;
this.amount = amount;
}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java
index 43b2c275..1dea8280 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java
@@ -1,6 +1,7 @@
package com.messagebird.objects.conversations;
import java.util.Date;
+import java.util.Map;
/**
* Response object that represents a conversation's message. Messages can be
@@ -12,12 +13,20 @@ public class ConversationMessage {
private String id;
private String conversationId;
private String channelId;
+ private String trackId;
private ConversationMessageDirection direction;
private ConversationMessageStatus status;
private ConversationContentType type;
private ConversationContent content;
private Date createdDatetime;
private Date updatedDatetime;
+ private Map source;
+ private ConversationMessageTag tag;
+ private ConversationMessageMetadata metadata;
+ /**
+ * See: {@link ConversationPlatformConstants}
+ */
+ private String platform;
public String getId() {
return id;
@@ -91,6 +100,46 @@ public void setUpdatedDatetime(Date updatedDatetime) {
this.updatedDatetime = updatedDatetime;
}
+ public Map getSource() {
+ return source;
+ }
+
+ public void setSource(Map source) {
+ this.source = source;
+ }
+
+ public ConversationMessageTag getTag() {
+ return tag;
+ }
+
+ public void setTag(ConversationMessageTag tag) {
+ this.tag = tag;
+ }
+
+ public ConversationMessageMetadata getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(ConversationMessageMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ public String getPlatform() {
+ return platform;
+ }
+
+ public void setPlatform(String platform) {
+ this.platform = platform;
+ }
+
+ public String getTrackId() {
+ return trackId;
+ }
+
+ public void setTrackId(String trackId) {
+ this.trackId = trackId;
+ }
+
@Override
public String toString() {
return "ConversationMessage{" +
@@ -100,9 +149,14 @@ public String toString() {
", direction=" + direction +
", status=" + status +
", type=" + type +
+ ", trackID=" + trackId +
", content=" + content +
", createdDatetime=" + createdDatetime +
", updatedDatetime=" + updatedDatetime +
+ ", source=" + source +
+ ", tag=" + tag +
+ ", metadata=" + metadata +
+ ", platform='" + platform + '\'' +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java
new file mode 100644
index 00000000..c41e814b
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java
@@ -0,0 +1,42 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import java.util.Date;
+
+/**
+ * Inner metadata attached to a conversation message. Present on both incoming
+ * messages and status webhook payloads. {@code sender.userId} always contains
+ * the BSUID when Meta provides one. When both identifiers exist, the phone
+ * number appears in the parent {@code from} field, not in this object.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConversationMessageMetadata {
+
+ private ConversationSenderMetadata sender;
+ private Date receivedAt;
+
+ public ConversationSenderMetadata getSender() {
+ return sender;
+ }
+
+ public void setSender(ConversationSenderMetadata sender) {
+ this.sender = sender;
+ }
+
+ public Date getReceivedAt() {
+ return receivedAt;
+ }
+
+ public void setReceivedAt(Date receivedAt) {
+ this.receivedAt = receivedAt;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationMessageMetadata{" +
+ "sender=" + sender +
+ ", receivedAt=" + receivedAt +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageRequest.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageRequest.java
index 5607c147..420213e3 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageRequest.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageRequest.java
@@ -1,5 +1,7 @@
package com.messagebird.objects.conversations;
+import java.util.Map;
+
/**
* Request object that is used to send new messages over a channel.
*/
@@ -8,6 +10,10 @@ public class ConversationMessageRequest {
private ConversationContentType type;
private ConversationContent content;
private String channelId;
+ private String reportUrl;
+ private String trackId;
+ private String ttl;
+ private Map source;
public ConversationContentType getType() {
return type;
@@ -33,12 +39,47 @@ public void setChannelId(String channelId) {
this.channelId = channelId;
}
+ public String getReportUrl() {
+ return reportUrl;
+ }
+
+ public void setReportUrl(String reportUrl) {
+ this.reportUrl = reportUrl;
+ }
+
+ public Map getSource() {
+ return source;
+ }
+
+ public void setSource(Map source) {
+ this.source = source;
+ }
+
+ public String getTrackId() {
+ return trackId;
+ }
+
+ public void setTrackId(String trackId) {
+ this.trackId = trackId;
+ }
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+
@Override
public String toString() {
return "ConversationMessageRequest{" +
"type=" + type +
", content=" + content +
", channelId='" + channelId + '\'' +
+ ", reportUrl='" + reportUrl + '\'' +
+ ", source=" + source +
+ ", trackID=" + trackId +
+ ", ttl=" + ttl +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageStatus.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageStatus.java
index 475c7b74..aee5c5f5 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageStatus.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageStatus.java
@@ -15,7 +15,25 @@ public enum ConversationMessageStatus {
READ("read"),
RECEIVED("received"),
SENT("sent"),
- UNSUPPORTED("unsupported");
+ UNSUPPORTED("unsupported"),
+ ACCEPTED("accepted"),
+ REJECTED("rejected"),
+ UNKNOWN("unknown"),
+ //WA specific statuses
+ TRANSMITTED("transmitted"),
+ //SMS specific statuses
+ DELIVERY_FAILED("delivery_failed"),
+ BUFFERED("buffered"),
+ EXPIRED("expired"),
+ //Email specific statuses
+ CLICKED("clicked"),
+ OPENED("opened"),
+ BOUNCE("bounce"),
+ SPAM_COMPLAINT("spam_complaint"),
+ OUT_OF_BOUNDED("out_of_bounded"),
+ DELAYED("delayed"),
+ LIST_UNSUBSCRIBE("list_unsubscribe"),
+ DISPATCHED("dispatched");
private final String status;
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageTag.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageTag.java
new file mode 100644
index 00000000..49314b3c
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageTag.java
@@ -0,0 +1,41 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * These allow tagging a message based on Facebook tags.
+ * For more information visit: https://developers.facebook.com/docs/messenger-platform/send-messages/message-tags/
+ */
+public enum ConversationMessageTag {
+ EventUpdate("event.update"),
+ PurchaseUpdate("purchase.update"),
+ AccountUpdate("account.update"),
+ HumanAgent("human_agent");
+
+ @JsonValue
+ private final String tag;
+
+ ConversationMessageTag(String tag) {
+ this.tag = tag;
+ }
+
+ @JsonCreator
+ public static ConversationMessageTag forValue(final String value) {
+ for (ConversationMessageTag tag : ConversationMessageTag.values()) {
+ if (tag.getTag().equals(value)) {
+ return tag;
+ }
+ }
+ return null;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ @Override
+ public String toString() {
+ return tag;
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationPlatformConstants.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationPlatformConstants.java
new file mode 100644
index 00000000..b9c02f49
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationPlatformConstants.java
@@ -0,0 +1,33 @@
+package com.messagebird.objects.conversations;
+
+/**
+ * Platforms are communication channels that a conversation can communicate through.
+ */
+public class ConversationPlatformConstants {
+ // PlatformSMS identifies the MessageBird SMS platform.
+ public static final String SMS = "sms";
+
+ // PlatformWhatsApp identifies the WhatsApp platform.
+ public static final String WHATSAPP = "whatsapp";
+
+ // PlatformFacebook identifies the Facebook platform.
+ public static final String FACEBOOK = "facebook";
+
+ // PlatformTelegram identifies the Telegram platform.
+ public static final String TELEGRAM = "telegram";
+
+ // PlatformLine identifies the LINE platform.
+ public static final String LINE = "line";
+
+ // PlatformWeChat identifies the WeChat platform.
+ public static final String WECHAT = "wechat";
+
+ // PlatformEmail identifies the Email platform.
+ public static final String EMAIL = "email";
+
+ // PlatformEvents identifies the Events platform
+ public static final String EVENTS = "events";
+
+ // PlatformWhatsAppSandbox identified the WhatsApp sandbox platform.
+ public static final String WHATSAPP_SANDBOX = "whatsapp_sandbox";
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java
new file mode 100644
index 00000000..7537da85
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java
@@ -0,0 +1,50 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+/**
+ * Identifies the recipient of an outbound WhatsApp message, as reported back on
+ * status webhook payloads under {@code status.metadata.recipient}. Mirrors
+ * {@link ConversationSenderMetadata} on the inbound side.
+ *
+ * {@code userId} is the recipient's BSUID (e.g. "US.13491208655302741918");
+ * {@code parentUserId} is the parent business-scoped user ID of the enterprise
+ * that owns the business portfolio it was scoped against (e.g.
+ * "US.ENT.11815799212886844830").
+ *
+ *
Either field may be {@code null}: Meta only supplies them for accounts
+ * enrolled in the BSUID rollout, and the enclosing {@code recipient} object is
+ * omitted entirely when neither is present. This is the only place a status
+ * payload carries the recipient's own identity — {@code messageMetadata.to} is
+ * an echo of the address the message was addressed to.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConversationRecipientMetadata {
+
+ private String userId;
+ private String parentUserId;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getParentUserId() {
+ return parentUserId;
+ }
+
+ public void setParentUserId(String parentUserId) {
+ this.parentUserId = parentUserId;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationRecipientMetadata{" +
+ "userId='" + userId + '\'' +
+ ", parentUserId='" + parentUserId + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSendRequest.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSendRequest.java
new file mode 100644
index 00000000..40ace8d7
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSendRequest.java
@@ -0,0 +1,125 @@
+package com.messagebird.objects.conversations;
+
+import java.util.Map;
+
+public class ConversationSendRequest {
+ private String to;
+ private ConversationContentType type;
+ private ConversationContent content;
+ private String from;
+ private String reportUrl;
+ private String trackId;
+ private String ttl;
+ private ConversationFallbackOption fallback;
+ private Map source;
+ private ConversationMessageTag tag;
+
+ public ConversationSendRequest(String to, ConversationContentType type, ConversationContent content, String from, String reportUrl, ConversationFallbackOption fallback, Map source, ConversationMessageTag tag) {
+ this.to = to;
+ this.type = type;
+ this.content = content;
+ this.from = from;
+ this.reportUrl = reportUrl;
+ this.fallback = fallback;
+ this.source = source;
+ this.tag = tag;
+ }
+
+ public ConversationSendRequest() {
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ public ConversationContentType getType() {
+ return type;
+ }
+
+ public void setType(ConversationContentType type) {
+ this.type = type;
+ }
+
+ public ConversationContent getContent() {
+ return content;
+ }
+
+ public void setContent(ConversationContent content) {
+ this.content = content;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getReportUrl() {
+ return reportUrl;
+ }
+
+ public void setReportUrl(String reportUrl) {
+ this.reportUrl = reportUrl;
+ }
+
+ public ConversationFallbackOption getFallback() {
+ return fallback;
+ }
+
+ public void setFallback(ConversationFallbackOption fallback) {
+ this.fallback = fallback;
+ }
+
+ public Map getSource() {
+ return source;
+ }
+
+ public void setSource(Map source) {
+ this.source = source;
+ }
+
+ public ConversationMessageTag getTag() {
+ return tag;
+ }
+
+ public void setTag(ConversationMessageTag tag) {
+ this.tag = tag;
+ }
+
+ public void setTrackId(String trackId) {
+ this.trackId = trackId;
+ }
+
+ public String getTrackId() {
+ return trackId;
+ }
+
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+ @Override
+ public String toString() {
+ return "ConversationSendRequest{" +
+ "to='" + to + '\'' +
+ ", type=" + type +
+ ", content=" + content +
+ ", from='" + from + '\'' +
+ ", reportUrl='" + reportUrl + '\'' +
+ ", trackId='" + trackId + '\'' +
+ ", ttl='" + ttl + '\'' +
+ ", fallback=" + fallback + '\'' +
+ ", tags=" + tag +
+ ", source='" + source + '\'' +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSendResponse.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSendResponse.java
new file mode 100644
index 00000000..8d928df6
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSendResponse.java
@@ -0,0 +1,60 @@
+package com.messagebird.objects.conversations;
+
+public class ConversationSendResponse {
+ private String id; //messageID
+ private String status;
+ private FallbackOptionResponse fallback;
+
+ public static class FallbackOptionResponse{
+ private String id;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "FallbackOptionResponse{" +
+ "id='" + id + '\'' +
+ '}';
+ }
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public FallbackOptionResponse getFallback() {
+ return fallback;
+ }
+
+ public void setFallback(FallbackOptionResponse fallback) {
+ this.fallback = fallback;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationSendResponse{" +
+ "id='" + id + '\'' +
+ ", status='" + status + '\'' +
+ ", fallback=" + fallback +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java
new file mode 100644
index 00000000..b7fdcbb0
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java
@@ -0,0 +1,66 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+/**
+ * Metadata about the sender of a WhatsApp message. {@code userId} always
+ * contains the BSUID (e.g. "US.13491208655302741918") when Meta supplies one.
+ * When both a phone number and a BSUID are available, the phone number appears
+ * in the parent message's {@code from} field — not here.
+ *
+ * {@code parentUserId} carries the sender's parent business-scoped user ID
+ * (e.g. "US.ENT.11815799212886844830"), which identifies the enterprise that
+ * owns the business portfolio the {@code userId} was scoped against. It is only
+ * present for accounts enrolled in Meta's parent-BSUID rollout; for everyone
+ * else it stays {@code null}.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConversationSenderMetadata {
+
+ private String userId;
+ private String parentUserId;
+ private String username;
+ private String displayName;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getParentUserId() {
+ return parentUserId;
+ }
+
+ public void setParentUserId(String parentUserId) {
+ this.parentUserId = parentUserId;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationSenderMetadata{" +
+ "userId='" + userId + '\'' +
+ ", parentUserId='" + parentUserId + '\'' +
+ ", username='" + username + '\'' +
+ ", displayName='" + displayName + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStartRequest.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStartRequest.java
index 9779bf5c..6f7c84fe 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationStartRequest.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStartRequest.java
@@ -1,5 +1,7 @@
package com.messagebird.objects.conversations;
+import java.util.Map;
+
/**
* Request object used for starting a conversation.
*/
@@ -8,18 +10,27 @@ public class ConversationStartRequest {
private String to;
private ConversationContentType type;
private ConversationContent content;
+ private Map source;
+ private ConversationMessageTag tag;
private String channelId;
+ private String reportUrl;
+ private String trackId;
+ private String ttl;
public ConversationStartRequest(
final String to,
final ConversationContentType type,
final ConversationContent content,
- final String channelId
+ final String channelId,
+ final Map source,
+ final ConversationMessageTag tag
) {
this.to = to;
this.type = type;
this.content = content;
this.channelId = channelId;
+ this.source = source;
+ this.tag = tag;
}
public ConversationStartRequest() {
@@ -58,13 +69,50 @@ public void setChannelId(final String channelId) {
this.channelId = channelId;
}
+ public String getReportUrl() {
+ return reportUrl;
+ }
+
+ public void setReportUrl(final String reportUrl) {
+ this.reportUrl = reportUrl;
+ }
+
+ public Map getSource() {
+ return source;
+ }
+
+ public void setSource(Map source) {
+ this.source = source;
+ }
+
+ public ConversationMessageTag getTag() {
+ return tag;
+ }
+
+ public void setTag(ConversationMessageTag tag) {
+ this.tag = tag;
+ }
+
+ public String getTrackId() {
+ return trackId;
+ }
+
+ public void setTrackId(String trackId) {
+ this.trackId = trackId;
+ }
+
@Override
public String toString() {
return "ConversationStartRequest{" +
"to='" + to + '\'' +
", type=" + type +
", content=" + content +
+ ", source=" + source +
+ ", tag=" + tag +
", channelId='" + channelId + '\'' +
+ ", reportUrl='" + reportUrl + '\'' +
+ ", trackId='" + trackId + '\'' +
+ ", ttl='" + ttl + '\'' +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java
new file mode 100644
index 00000000..47a4a8d1
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java
@@ -0,0 +1,92 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+/**
+ * The {@code messageMetadata} block delivered inside status webhook payloads
+ * (e.g. {@code statusSent}, {@code statusDelivered}). Reflects the original
+ * message that triggered the status update.
+ *
+ * This class is not produced by any SDK request — it is a standalone POJO
+ * intended for consumers who deserialize incoming webhook payloads in their
+ * own HTTP handlers. Use it via {@code ObjectMapper.readValue(body, ...)}.
+ *
+ *
Both {@code from} and {@code to} accept either a phone number or a
+ * WhatsApp Business-Scoped User ID (BSUID, e.g. "US.13491208655302741918").
+ * The BSUID is also available via {@code metadata.sender.userId}.
+ *
+ *
{@code to} echoes back the address the message was originally addressed
+ * to, so it is not a reliable source of the recipient's BSUID. That identity
+ * lives alongside this block, under {@code status.metadata.recipient} — see
+ * {@link ConversationStatusMetadata}.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConversationStatusMessageMetadata {
+
+ private String id;
+ private String from;
+ private String to;
+ private String type;
+ private ConversationContent content;
+ private ConversationMessageMetadata metadata;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public ConversationContent getContent() {
+ return content;
+ }
+
+ public void setContent(ConversationContent content) {
+ this.content = content;
+ }
+
+ public ConversationMessageMetadata getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(ConversationMessageMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationStatusMessageMetadata{" +
+ "id='" + id + '\'' +
+ ", from='" + from + '\'' +
+ ", to='" + to + '\'' +
+ ", type='" + type + '\'' +
+ ", content=" + content +
+ ", metadata=" + metadata +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java
new file mode 100644
index 00000000..0b4d5f7f
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java
@@ -0,0 +1,85 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * The {@code status.metadata} block delivered inside status webhook payloads
+ * (e.g. {@code statusSent}, {@code statusDelivered}).
+ *
+ *
This class is not produced by any SDK request — it is a standalone POJO
+ * intended for consumers who deserialize incoming webhook payloads in their own
+ * HTTP handlers. Use it via {@code ObjectMapper.readValue(body, ...)}.
+ *
+ *
Note the mixed casing of this object. {@code pricing} and
+ * {@code conversation} are near-verbatim passthroughs of Meta's own objects and
+ * so keep their snake_case keys ({@code pricing_model}, {@code category}, …);
+ * they are exposed here as raw maps rather than modelled types, because their
+ * contents track Meta's schema rather than ours. {@code recipient} is ours and
+ * follows the camelCase convention used everywhere else in the API. Any other
+ * key present on the payload — for example {@code biz_opaque_callback_data} —
+ * is collected into {@link #getAdditionalProperties()} rather than dropped.
+ *
+ *
{@code recipient} is absent from payloads for accounts that never receive
+ * BSUIDs, in which case {@link #getRecipient()} returns {@code null}.
+ */
+public class ConversationStatusMetadata {
+
+ private Map pricing;
+ private Map conversation;
+ private ConversationRecipientMetadata recipient;
+ private final Map additionalProperties = new LinkedHashMap<>();
+
+ public Map getPricing() {
+ return pricing;
+ }
+
+ public void setPricing(Map pricing) {
+ this.pricing = pricing;
+ }
+
+ public Map getConversation() {
+ return conversation;
+ }
+
+ public void setConversation(Map conversation) {
+ this.conversation = conversation;
+ }
+
+ public ConversationRecipientMetadata getRecipient() {
+ return recipient;
+ }
+
+ public void setRecipient(ConversationRecipientMetadata recipient) {
+ this.recipient = recipient;
+ }
+
+ /**
+ * Every key on the payload that has no dedicated accessor above, in the
+ * order it was encountered. Empty when the payload holds nothing else.
+ *
+ * @return the unmodelled remainder of the metadata object
+ */
+ @JsonAnyGetter
+ public Map getAdditionalProperties() {
+ return additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ additionalProperties.put(name, value);
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationStatusMetadata{" +
+ "pricing=" + pricing +
+ ", conversation=" + conversation +
+ ", recipient=" + recipient +
+ ", additionalProperties=" + additionalProperties +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationUpdateRequest.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationUpdateRequest.java
new file mode 100644
index 00000000..9a67a516
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationUpdateRequest.java
@@ -0,0 +1,29 @@
+package com.messagebird.objects.conversations;
+
+import java.util.Objects;
+
+public class ConversationUpdateRequest {
+
+ private final ConversationStatus status;
+
+ public ConversationUpdateRequest(ConversationStatus status) {
+ this.status = status;
+ }
+
+ public ConversationStatus getStatus() {
+ return status;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ConversationUpdateRequest that = (ConversationUpdateRequest) o;
+ return status == that.status;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(status);
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationWebhookCreateRequest.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationWebhookCreateRequest.java
index 1b7c3864..24cf7f9a 100644
--- a/api/src/main/java/com/messagebird/objects/conversations/ConversationWebhookCreateRequest.java
+++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationWebhookCreateRequest.java
@@ -28,4 +28,8 @@ protected String getRequestName() {
protected String getStringRepresentationOfExtraParameters() {
return "channelId='" + channelId;
}
+
+ public String getChannelId() {
+ return channelId;
+ }
}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/HSMCurrency.java b/api/src/main/java/com/messagebird/objects/conversations/HSMCurrency.java
new file mode 100644
index 00000000..24ea4be6
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/HSMCurrency.java
@@ -0,0 +1,31 @@
+package com.messagebird.objects.conversations;
+
+public class HSMCurrency {
+
+ private String currencyCode;
+ private int amount;
+
+ public String getCurrencyCode() {
+ return currencyCode;
+ }
+
+ public void setCurrencyCode(String currencyCode) {
+ this.currencyCode = currencyCode;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return "HSMCurrency{" +
+ "currencyCode='" + currencyCode + '\'' +
+ ", amount=" + amount +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/Media.java b/api/src/main/java/com/messagebird/objects/conversations/Media.java
new file mode 100644
index 00000000..4a9bf4ea
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/Media.java
@@ -0,0 +1,31 @@
+package com.messagebird.objects.conversations;
+
+public class Media {
+
+ private String url;
+ private String caption;
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ @Override
+ public String toString() {
+ return "Media{" +
+ "url='" + url + '\'' +
+ ", caption='" + caption + '\'' +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java
new file mode 100644
index 00000000..d3a7c20b
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java
@@ -0,0 +1,82 @@
+package com.messagebird.objects.conversations;
+
+import java.util.List;
+
+public class MessageComponent {
+
+ private MessageComponentType type;
+ private String sub_type;
+ private int index;
+ private List parameters;
+ private int card_index;
+ private List cards;
+ private List components;
+
+ public void setType(MessageComponentType type) {
+ this.type = type;
+ }
+
+ public MessageComponentType getType() {
+ return type;
+ }
+
+ public String getSub_type() {
+ return sub_type;
+ }
+
+ public void setSub_type(String sub_type) {
+ this.sub_type = sub_type;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(List parameters) {
+ this.parameters = parameters;
+ }
+
+ public void setCards(List cards) {
+ this.cards = cards;
+ }
+
+ public List getCards() {
+ return cards;
+ }
+
+ public int getCard_index() {
+ return card_index;
+ }
+
+ public void setCard_index(int card_index) {
+ this.card_index = card_index;
+ }
+
+ public List getComponents() {
+ return components;
+ }
+
+ public void setComponents(List components) {
+ this.components = components;
+ }
+
+ @Override
+ public String toString() {
+ return "MessageComponent{" +
+ "type='" + type + '\'' +
+ ", sub_type='" + sub_type + '\'' +
+ ", index=" + index + '\'' +
+ ", parameters=" + parameters + '\'' +
+ ", components=" + components + '\'' +
+ ", cards=" + cards +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java
new file mode 100644
index 00000000..9f9290cf
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java
@@ -0,0 +1,54 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.*;
+
+public enum MessageComponentType {
+
+ HEADER("header"),
+ BODY("body"),
+ FOOTER("footer"),
+ BUTTON("button"),
+ CARD("card"),
+ CAROUSEL("carousel"),
+ LIMITED_TIME_OFFER("limited_time_offer"),
+ COPY_CODE("copy_code");
+
+ private static final Map TYPE_MAP;
+
+ static {
+ Map map = new HashMap<>();
+ for (MessageComponentType componentType : MessageComponentType.values()) {
+ map.put(componentType.getType().toLowerCase(), componentType);
+ }
+ TYPE_MAP = Collections.unmodifiableMap(map);
+ }
+
+ private final String type;
+
+ MessageComponentType(final String type) {
+ this.type = type;
+ }
+
+ @JsonCreator
+ public static MessageComponentType forValue(String value) {
+ Objects.requireNonNull(value, "Value cannot be null");
+ return TYPE_MAP.get(value.toLowerCase(Locale.ROOT));
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getType();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return getType();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java
new file mode 100644
index 00000000..6432369f
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java
@@ -0,0 +1,125 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.StringUtils;
+
+public class MessageParam {
+
+ private TemplateMediaType type;
+ private String text;
+ private String payload;
+ private HSMCurrency currency;
+ private String dateTime;
+ private Media document;
+ private Media image;
+ private Media video;
+ @JsonProperty("expiration_time")
+ private String expirationTime;
+ @JsonProperty("coupon_code")
+ private String couponCode;
+
+ public TemplateMediaType getType() {
+ return type;
+ }
+
+ public void setType(TemplateMediaType type) {
+ this.type = type;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ if (StringUtils.isBlank(text)) {
+ throw new IllegalArgumentException("Text cannot be null or empty");
+ }
+ this.text = text;
+ }
+
+ public String getPayload() {
+ return payload;
+ }
+
+ public void setPayload(String payload) {
+ this.payload = payload;
+ }
+
+ public HSMCurrency getCurrency() {
+ return currency;
+ }
+
+ public void setCurrency(HSMCurrency currency) {
+ this.currency = currency;
+ }
+
+ public String getDateTime() {
+ return dateTime;
+ }
+
+ public void setDateTime(String dateTime) {
+ if (StringUtils.isBlank(dateTime)) {
+ throw new IllegalArgumentException("dateTime cannot be null or empty");
+ }
+ this.dateTime = dateTime;
+ }
+
+ public Media getDocument() {
+ return document;
+ }
+
+ public void setDocument(Media document) {
+ this.document = document;
+ }
+
+ public Media getImage() {
+ return image;
+ }
+
+ public void setImage(Media image) {
+ this.image = image;
+ }
+
+ public Media getVideo() { return video; }
+
+ public void setVideo(Media video) { this.video = video; }
+
+ public String getExpirationTime() {
+ return expirationTime;
+ }
+
+ public void setExpirationTime(String expirationTime) {
+ if (StringUtils.isBlank(expirationTime)) {
+ throw new IllegalArgumentException("expirationTime cannot be null or empty");
+ }
+ this.expirationTime = expirationTime;
+ }
+
+ public String getCouponCode() {
+ return couponCode;
+ }
+
+ public void setCouponCode(String couponCode) {
+ if (StringUtils.isBlank(couponCode)) {
+ throw new IllegalArgumentException("couponCode cannot be null or empty");
+ }
+ this.couponCode = couponCode;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("MessageParam{");
+ sb.append("type=").append(type)
+ .append(", text='").append(text).append('\'')
+ .append(", payload='").append(payload).append('\'')
+ .append(", currency=").append(currency)
+ .append(", dateTime='").append(dateTime).append('\'')
+ .append(", document=").append(document)
+ .append(", image=").append(image)
+ .append(", video=").append(video)
+ .append(", expirationTime='").append(expirationTime).append('\'')
+ .append(", couponCode='").append(couponCode).append('\'')
+ .append('}');
+ return sb.toString();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java
new file mode 100644
index 00000000..580dcc97
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java
@@ -0,0 +1,60 @@
+package com.messagebird.objects.conversations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+
+public enum TemplateMediaType {
+
+ IMAGE("image"),
+ DOCUMENT("document"),
+ VIDEO("video"),
+ TEXT("text"),
+ CURRENCY("currency"),
+ DATETIME("date_time"),
+ PAYLOAD("payload"),
+ EXPIRATION_TIME("expiration_time"),
+ COUPON_CODE("coupon_code");
+
+ private static final Map TYPE_MAP;
+
+ static {
+ Map map = new HashMap<>();
+ for (TemplateMediaType templateMediaType : TemplateMediaType.values()) {
+ map.put(templateMediaType.getType().toLowerCase(), templateMediaType);
+ }
+ TYPE_MAP = Collections.unmodifiableMap(map);
+ }
+
+
+ private final String type;
+
+ TemplateMediaType(final String type) {
+ this.type = type;
+ }
+
+ @JsonCreator
+ public static TemplateMediaType forValue(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("Value cannot be null");
+ }
+ return TYPE_MAP.get(value.toLowerCase());
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getType();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return getType();
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java b/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java
new file mode 100644
index 00000000..3edb1db9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java
@@ -0,0 +1,48 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * An enum for HSMComponentFormat
+ *
+ * @see HSMComponentFormat
+ * @author ssk910
+ */
+public enum HSMCategory {
+
+ AUTHENTICATION("AUTHENTICATION"),
+ UTILITY("UTILITY"),
+ MARKETING("MARKETING");
+
+ private final String category;
+
+ HSMCategory(String category) {
+ this.category = category;
+ }
+
+ @JsonCreator
+ public static HSMCategory forValue(String value) {
+ for (HSMCategory hsmCategory : HSMCategory.values()) {
+ if (hsmCategory.getCategory().equals(value)) {
+ return hsmCategory;
+ }
+ }
+
+ return null;
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getCategory();
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ @Override
+ public String toString() {
+ return getCategory();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java
new file mode 100644
index 00000000..ed93847f
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java
@@ -0,0 +1,196 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * A class for HSMComponent object
+ *
+ * @see HSMComponent
+ * @author ssk910
+ */
+public class HSMComponent {
+
+ private HSMComponentType type;
+ private HSMComponentFormat format;
+ private String text;
+ @JsonProperty("add_security_recommendation")
+ private Boolean addSecurityRecommendation;
+ @JsonProperty("code_expiration_minutes")
+ private Integer codeExpirationMinutes;
+ private List buttons;
+ @JsonProperty("has_expiration")
+ private Boolean hasExpiration;
+
+ private List cards;
+
+ private HSMExample example;
+
+ public HSMComponentType getType() {
+ return type;
+ }
+
+ public void setType(HSMComponentType type) {
+ this.type = type;
+ }
+
+ public HSMComponentFormat getFormat() {
+ return format;
+ }
+
+ public void setFormat(HSMComponentFormat format) {
+ this.format = format;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ if (StringUtils.isBlank(text)) {
+ throw new IllegalArgumentException("Text cannot be null or empty");
+ }
+ this.text = text;
+ }
+
+ public List getButtons() {
+ return buttons;
+ }
+
+ public void setButtons(List buttons) {
+ this.buttons = buttons;
+ }
+
+ public List getCards() {
+ return cards;
+ }
+
+ public void setCards(List cards) {
+ this.cards = cards;
+ }
+
+ public HSMExample getExample() {
+ return example;
+ }
+
+ public void setExample(HSMExample example) {
+ this.example = example;
+ }
+
+ public Boolean getAddSecurityRecommendation() {
+ return addSecurityRecommendation;
+ }
+
+ public void setAddSecurityRecommendation(Boolean addSecurityRecommendation) {
+ this.addSecurityRecommendation = addSecurityRecommendation;
+ }
+
+ public Integer getCodeExpirationMinutes() {
+ return codeExpirationMinutes;
+ }
+
+ public void setCodeExpirationMinutes(Integer codeExpirationMinutes) {
+ this.codeExpirationMinutes = codeExpirationMinutes;
+ }
+
+ public Boolean getHasExpiration() {
+ return hasExpiration;
+ }
+
+ public void setHasExpiration(Boolean hasExpiration) {
+ this.hasExpiration = hasExpiration;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("HSMComponent{");
+ sb.append("type=").append(type)
+ .append(", format=").append(format)
+ .append(", text='").append(text).append('\'')
+ .append(", addSecurityRecommendation=").append(addSecurityRecommendation)
+ .append(", codeExpirationMinutes=").append(codeExpirationMinutes)
+ .append(", buttons=").append(buttons)
+ .append(", hasExpiration=").append(hasExpiration)
+ .append(", cards=").append(cards)
+ .append(", example=").append(example)
+ .append('}');
+ return sb.toString();
+ }
+
+ /**
+ * Check if this component is valid.
+ *
+ * @throws IllegalArgumentException Occurs when validation is not passed.
+ */
+ public void validateComponent() throws IllegalArgumentException {
+ try {
+ this.validateButtons();
+ this.validateComponentExample();
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Component validation failed: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Check if button list is valid.
+ *
+ * @throws IllegalArgumentException Occurs when validation is not passed.
+ */
+ private void validateButtons() throws IllegalArgumentException {
+ if (this.buttons == null) {
+ return;
+ }
+
+ for (final HSMComponentButton button : this.buttons) {
+ button.validateButtonExample();
+ }
+ }
+
+ /**
+ * Check for header_text and header_url.
+ *
+ * @throws IllegalArgumentException Occurs when {@code header_text} or {@code header_url} is not able to use.
+ */
+ private void validateComponentExample() throws IllegalArgumentException {
+ final boolean isExampleNotNull = this.example != null;
+ final boolean isHeaderTextNotEmpty =
+ isExampleNotNull && !(this.example.getHeader_text() == null || this.example.getHeader_text()
+ .isEmpty());
+ final boolean isHeaderUrlNotEmpty =
+ isExampleNotNull && !(this.example.getHeader_url() == null || this.example.getHeader_url()
+ .isEmpty());
+
+ if (isHeaderTextNotEmpty) {
+ this.checkHeaderText();
+ }
+
+ if (isHeaderUrlNotEmpty) {
+ this.checkHeaderUrl();
+ }
+ }
+
+ /**
+ * Check if header_text is able to use.
+ *
+ * @throws IllegalArgumentException Occurs when type is not {@code HEADER} and format is not {@code TEXT}.
+ */
+ private void checkHeaderText() throws IllegalArgumentException {
+ if (!(HSMComponentType.HEADER.equals(type) && HSMComponentFormat.TEXT.equals(format))) {
+ throw new IllegalArgumentException("\"header_text\" is available for only HEADER type and TEXT format.");
+ }
+ }
+
+ /**
+ * Check if header_url is able to use.
+ *
+ * @throws IllegalArgumentException Occurs when type is not {@code HEADER} and format is not {@code IMAGE}.
+ */
+ private void checkHeaderUrl() throws IllegalArgumentException {
+ if (!(HSMComponentType.HEADER.equals(type) &&
+ (HSMComponentFormat.IMAGE.equals(format) || HSMComponentFormat.VIDEO.equals(format) || HSMComponentFormat.DOCUMENT.equals(format)))) {
+ throw new IllegalArgumentException("\"header_url\" is available for only HEADER type and IMAGE, VIDEO, or DOCUMENT formats.");
+ }
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java
new file mode 100644
index 00000000..75204df0
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java
@@ -0,0 +1,132 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+/**
+ * HSMComponentButton
+ *
+ * @see HSMComponentButton
+ * @author ssk910
+ */
+public class HSMComponentButton {
+
+ private HSMComponentButtonType type;
+ private String text;
+ private String url;
+ private String phone_number;
+ private List example;
+
+ //fields used by the authentification template
+ @JsonProperty("otp_type")
+ private HSMOTPButtonType otpType;
+ @JsonProperty("autofill_text")
+ private String autofillText;
+ @JsonProperty("package_name")
+ private String packageName;
+ @JsonProperty("signature_hash")
+ private String signatureHash;
+
+ public HSMComponentButtonType getType() {
+ return type;
+ }
+
+ public void setType(HSMComponentButtonType type) {
+ this.type = type;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getPhone_number() {
+ return phone_number;
+ }
+
+ public void setPhone_number(String phone_number) {
+ this.phone_number = phone_number;
+ }
+
+ public List getExample() {
+ return example;
+ }
+
+ public void setExample(List example) {
+ this.example = example;
+ }
+ public HSMOTPButtonType getOtpType() {
+ return otpType;
+ }
+
+ public void setOtpType(HSMOTPButtonType otpType) {
+ this.otpType = otpType;
+ }
+
+ public String getAutofillText() {
+ return autofillText;
+ }
+
+ public void setAutofillText(String autofillText) {
+ this.autofillText = autofillText;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public String getSignatureHash() {
+ return signatureHash;
+ }
+
+ public void setSignatureHash(String signatureHash) {
+ this.signatureHash = signatureHash;
+ }
+ @Override
+ public String toString() {
+ return "HSMComponentButton{" +
+ "type=" + type +
+ ", text='" + text + '\'' +
+ ", url='" + url + '\'' +
+ ", phone_number='" + phone_number + '\'' +
+ ", example=" + example +
+ '}';
+ }
+
+ /**
+ * Check if example field is able to use.
+ *
+ * @throws IllegalArgumentException Occurs if button type is not {@code URL} or {@code QUICK_REPLY}.
+ */
+ public void validateButtonExample() throws IllegalArgumentException {
+ final boolean isExampleEmpty = this.example == null || this.example.isEmpty();
+ final boolean isNotProperType = !(this.type.equals(HSMComponentButtonType.URL)
+ || this.type.equals(HSMComponentButtonType.QUICK_REPLY)
+ || this.type.equals(HSMComponentButtonType.COPY_CODE)
+ );
+
+ if (isExampleEmpty) {
+ return;
+ }
+
+ if (isNotProperType) {
+ throw new IllegalArgumentException("An example field in HSMComponentButton is available for only URL or QUICK_REPLY button types.");
+ }
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java
new file mode 100644
index 00000000..06e6eb91
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java
@@ -0,0 +1,50 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * HSMComponentButtonType
+ *
+ * @see HSMComponentButtonType
+ * @author ssk910
+ */
+public enum HSMComponentButtonType {
+
+ PHONE_NUMBER("PHONE_NUMBER"),
+ URL("URL"),
+ QUICK_REPLY("QUICK_REPLY"),
+ OTP("OTP"),
+ COPY_CODE("COPY_CODE");
+
+ private final String type;
+
+ HSMComponentButtonType(String type) {
+ this.type = type;
+ }
+
+ @JsonCreator
+ public static HSMComponentButtonType forValue(String value) {
+ for (HSMComponentButtonType hsmComponentButtonType : HSMComponentButtonType.values()) {
+ if (hsmComponentButtonType.getType().equals(value)) {
+ return hsmComponentButtonType;
+ }
+ }
+
+ return null;
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getType();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return getType();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java
new file mode 100644
index 00000000..23411941
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java
@@ -0,0 +1,21 @@
+package com.messagebird.objects.integrations;
+
+import java.util.List;
+
+/**
+ * HSMComponentCard
+ *
+ * @author AlexL-mb
+ * @see HSMComponentCard
+ */
+public class HSMComponentCard {
+ private List components;
+
+ public List getComponents() {
+ return components;
+ }
+
+ public void setComponents(List components) {
+ this.components = components;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentFormat.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentFormat.java
new file mode 100644
index 00000000..ac7d199d
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentFormat.java
@@ -0,0 +1,49 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * An enum for HSMComponentFormat
+ *
+ * @see HSMComponentFormat
+ * @author ssk910
+ */
+public enum HSMComponentFormat {
+
+ TEXT("TEXT"),
+ IMAGE("IMAGE"),
+ DOCUMENT("DOCUMENT"),
+ VIDEO("VIDEO");
+
+ private final String format;
+
+ HSMComponentFormat(String format) {
+ this.format = format;
+ }
+
+ @JsonCreator
+ public static HSMComponentFormat forValue(String value) {
+ for (HSMComponentFormat hsmComponentFormat : HSMComponentFormat.values()) {
+ if (hsmComponentFormat.getFormat().equals(value)) {
+ return hsmComponentFormat;
+ }
+ }
+
+ return null;
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getFormat();
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public String toString() {
+ return getFormat();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java
new file mode 100644
index 00000000..8610146a
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java
@@ -0,0 +1,59 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * An enum for HSMComponentType
+ *
+ * @see HSMComponentType
+ */
+public enum HSMComponentType {
+ BODY("BODY"),
+ HEADER("HEADER"),
+ FOOTER("FOOTER"),
+ BUTTONS("BUTTONS"),
+ CAROUSEL("CAROUSEL"),
+ LIMITED_TIME_OFFER("LIMITED_TIME_OFFER");
+
+ private static final Map TYPE_MAP;
+
+ static {
+ Map map = new HashMap<>();
+ for (HSMComponentType hsmComponentType : HSMComponentType.values()) {
+ map.put(hsmComponentType.getType().toLowerCase(), hsmComponentType);
+ }
+ TYPE_MAP = Collections.unmodifiableMap(map);
+ }
+
+ private final String type;
+
+ HSMComponentType(String type) {
+ this.type = type;
+ }
+
+ @JsonCreator
+ public static HSMComponentType forValue(String value) {
+ Objects.requireNonNull(value, "Value cannot be null");
+ return TYPE_MAP.get(value.toLowerCase(Locale.ROOT));
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getType();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return getType();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMExample.java b/api/src/main/java/com/messagebird/objects/integrations/HSMExample.java
new file mode 100644
index 00000000..a28fcc38
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMExample.java
@@ -0,0 +1,54 @@
+package com.messagebird.objects.integrations;
+
+import java.util.List;
+
+/**
+ * HSMExample object
+ *
+ * @see HSMExample object
+ * @author ssk910
+ */
+public class HSMExample {
+
+ /* Example values for HEADER type components, TEXT format */
+ private List header_text;
+
+ /* Example set of values for the body text variables */
+ private List> body_text;
+
+ /* Example values for HEADER type components, IMAGE format */
+ private List header_url;
+
+ public List getHeader_text() {
+ return header_text;
+ }
+
+ public void setHeader_text(List header_text) {
+ this.header_text = header_text;
+ }
+
+ public List> getBody_text() {
+ return body_text;
+ }
+
+ public void setBody_text(List> body_text) {
+ this.body_text = body_text;
+ }
+
+ public List getHeader_url() {
+ return header_url;
+ }
+
+ public void setHeader_url(List header_url) {
+ this.header_url = header_url;
+ }
+
+ @Override
+ public String toString() {
+ return "HSMExample{" +
+ "header_text=" + header_text +
+ ", body_text=" + body_text +
+ ", header_url=" + header_url +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java
new file mode 100644
index 00000000..499ef1f3
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java
@@ -0,0 +1,38 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum HSMOTPButtonType {
+ ONE_TAP("ONE_TAP"),
+ COPY_CODE("COPY_CODE");
+
+ private final String type;
+
+ HSMOTPButtonType(String type) {
+ this.type = type;
+ }
+ @JsonCreator
+ public static HSMOTPButtonType forValue(String value) {
+ for (HSMOTPButtonType OTPButtonType : HSMOTPButtonType.values()) {
+ if (OTPButtonType.getType().equals(value)) {
+ return OTPButtonType;
+ }
+ }
+ return null;
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getType();
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return getType();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java b/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java
new file mode 100644
index 00000000..112492fd
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java
@@ -0,0 +1,42 @@
+package com.messagebird.objects.integrations;
+
+import java.util.List;
+
+public class HSMQualityScore {
+ private String score;
+ private long date;
+ private List reasons;
+
+ public String getScore() {
+ return score;
+ }
+
+ public void setScore(String score) {
+ this.score = score;
+ }
+
+ public long getDate() {
+ return date;
+ }
+
+ public void setDate(long date) {
+ this.date = date;
+ }
+
+ public List getReasons() {
+ return reasons;
+ }
+
+ public void setReasons(List reasons) {
+ this.reasons = reasons;
+ }
+
+ @Override
+ public String toString() {
+ return "HSMQualityScore{" +
+ "score='" + score + '\'' +
+ ", date=" + date +
+ ", reasons=" + reasons +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java b/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java
new file mode 100644
index 00000000..1b1980f1
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java
@@ -0,0 +1,53 @@
+package com.messagebird.objects.integrations;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * An enum for HSMStatus object
+ *
+ * @see HSMStatus object
+ * @author ssk910
+ */
+public enum HSMStatus {
+
+ NEW("NEW"),
+ APPROVED("APPROVED"),
+ PENDING("PENDING"),
+ REJECTED("REJECTED"),
+ PENDING_DELETION("PENDING_DELETION"),
+ DELETED("DELETED"),
+ DISABLED("DISABLED"),
+ PAUSED("PAUSED");
+
+ private final String status;
+
+ HSMStatus(String status) {
+ this.status = status;
+ }
+
+ @JsonCreator
+ public static HSMStatus forValue(String value) {
+ for (HSMStatus hsmStatus : HSMStatus.values()) {
+ if (hsmStatus.getStatus().equals(value)) {
+ return hsmStatus;
+ }
+ }
+
+ return null;
+ }
+
+ @JsonValue
+ public String toJson() {
+ return getStatus();
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return getStatus();
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/Template.java b/api/src/main/java/com/messagebird/objects/integrations/Template.java
new file mode 100644
index 00000000..f6a83e93
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/Template.java
@@ -0,0 +1,173 @@
+package com.messagebird.objects.integrations;
+
+import java.util.List;
+
+/**
+ * Template Object as integrations API request.
+ *
+ * @see Integrations API
+ * @author ssk910
+ */
+public class Template {
+
+ private String name;
+ private String language;
+ private String wabaID;
+ private List components;
+ private HSMCategory category;
+ private boolean ctaURLLinkTrackingOptedOut;
+
+ public Template() {
+ }
+
+
+ public Template(String name, String language, String wabaID,
+ List components, HSMCategory category, boolean ctaURLLinkTrackingOptedOut) {
+ this.name = name;
+ this.language = language;
+ this.wabaID = wabaID;
+ this.components = components;
+ this.category = category;
+ this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getWABAID() {
+ return wabaID;
+ }
+
+ public void setWABAID(String wabaID) {
+ this.wabaID = wabaID;
+ }
+
+ public List getComponents() {
+ return components;
+ }
+
+ public void setComponents(List components) {
+ this.components = components;
+ }
+
+ public HSMCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(HSMCategory category) {
+ this.category = category;
+ }
+
+ public void setCtaURLLinkTrackingOptedOut (boolean ctaURLLinkTrackingOptedOut) {
+ this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut;
+ }
+
+ public boolean getCtaURLLinkTrackingOptedOut () {
+ return ctaURLLinkTrackingOptedOut;
+ }
+
+ @Override
+ public String toString() {
+ return "WhatsAppTemplate{" +
+ "name='" + name + '\'' +
+ ", language='" + language + '\'' +
+ ", wabaID='" + wabaID + '\'' +
+ ", components=" + components +
+ ", category='" + category + '\'' +
+ ", ctaURLLinkTrackingOptedOut='" + ctaURLLinkTrackingOptedOut + '\'' +
+ '}';
+ }
+
+ /**
+ * Validate required fields: components, name, language, category
+ *
+ * @throws IllegalArgumentException if required fields are invalid.
+ */
+ public void validate() throws IllegalArgumentException {
+ this.validateComponents();
+ this.validateName();
+ this.validateLanguage();
+ this.validateWABAID();
+ this.validateCategory();
+ }
+
+ /**
+ * Check if components field is valid.
+ *
+ * @throws IllegalArgumentException If components field is null or empty list.
+ */
+ private void validateComponents() throws IllegalArgumentException {
+ final boolean componentsNotEmpty = !(this.components == null || this.components.isEmpty());
+
+ if (componentsNotEmpty) {
+ for (final HSMComponent component : this.components) {
+ component.validateComponent();
+ }
+ } else {
+ throw new IllegalArgumentException("A \"components\" field is required and should not be empty list.");
+ }
+ }
+
+ /**
+ * Check if name field is valid.
+ *
+ * @throws IllegalArgumentException If name field is null or empty string.
+ */
+ private void validateName() {
+ if (this.name == null) {
+ throw new IllegalArgumentException("A \"name\" field is required.");
+ } else if (this.name.length() == 0) {
+ throw new IllegalArgumentException("A \"name\" field can not be an empty string.");
+ }
+ }
+
+ /**
+ * Check if language field is valid.
+ *
+ * @throws IllegalArgumentException If language field is null or empty string.
+ */
+ private void validateLanguage() {
+ if (this.language == null) {
+ throw new IllegalArgumentException("A \"language\" field is required.");
+ } else if (this.language.length() == 0) {
+ throw new IllegalArgumentException("A \"language\" field can not be an empty string.");
+ }
+ }
+
+ /**
+ * Check if wabaID field is valid.
+ *
+ * @throws IllegalArgumentException If wabaID field is null or empty string.
+ */
+ private void validateWABAID() {
+ if (this.wabaID == null) {
+ throw new IllegalArgumentException("A \"wabaID\" field is required.");
+ } else if (this.wabaID.length() == 0) {
+ throw new IllegalArgumentException("A \"wabaID\" field can not be an empty string.");
+ }
+ }
+
+ /**
+ * Check if category field is valid.
+ *
+ * @throws IllegalArgumentException If category field is null.
+ */
+ private void validateCategory() {
+ if (this.category == null) {
+ throw new IllegalArgumentException("A \"category\" field is required.");
+ }
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/TemplateList.java b/api/src/main/java/com/messagebird/objects/integrations/TemplateList.java
new file mode 100644
index 00000000..5cea4023
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/TemplateList.java
@@ -0,0 +1,12 @@
+package com.messagebird.objects.integrations;
+
+import com.messagebird.objects.ListBase;
+
+/**
+ * Response object representing the Template list type.
+ *
+ * @author ssk910
+ */
+public class TemplateList extends ListBase {
+
+}
diff --git a/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java b/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java
new file mode 100644
index 00000000..3c75fabe
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java
@@ -0,0 +1,149 @@
+package com.messagebird.objects.integrations;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Template response using integrations API.
+ *
+ * @author ssk910
+ */
+public class TemplateResponse implements Serializable {
+
+ private static final long serialVersionUID = 7154209824478715861L;
+ private String name;
+ private String language;
+ private HSMCategory category;
+ private List components;
+ private HSMStatus status;
+ private String rejectedReason;
+ private String wabaID;
+ private String namespace;
+
+ private boolean ctaURLLinkTrackingOptedOut;
+
+ private HSMQualityScore qualityScore;
+
+ private Date createdAt;
+ private Date updatedAt;
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public HSMCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(HSMCategory category) {
+ this.category = category;
+ }
+
+ public List getComponents() {
+ return components;
+ }
+
+ public void setComponents(List components) {
+ this.components = components;
+ }
+
+ public HSMStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(HSMStatus status) {
+ this.status = status;
+ }
+
+ public String getRejectedReason() {
+ return rejectedReason;
+ }
+
+ public void setRejectedReason(String rejectedReason) {
+ this.rejectedReason = rejectedReason;
+ }
+
+ public String getWabaID() {
+ return wabaID;
+ }
+
+ public void setWabaID(String wabaID) {
+ this.wabaID = wabaID;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public boolean isCtaURLLinkTrackingOptedOut() {
+ return ctaURLLinkTrackingOptedOut;
+ }
+
+ public void setCtaURLLinkTrackingOptedOut(boolean ctaURLLinkTrackingOptedOut) {
+ this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut;
+ }
+
+ public HSMQualityScore getQualityScore() {
+ return qualityScore;
+ }
+
+ public void setQualityScore(HSMQualityScore qualityScore) {
+ this.qualityScore = qualityScore;
+ }
+
+ @Override
+ public String toString() {
+ return "WhatsAppTemplateResponse{" +
+ "name='" + name + '\'' +
+ ", language='" + language + '\'' +
+ ", category='" + category + '\'' +
+ ", components=" + components +
+ ", status='" + status + '\'' +
+ ", rejectedReason='" + rejectedReason + '\'' +
+ ", wabaID='" + wabaID + '\'' +
+ ", namespace='" + namespace + '\'' +
+ ", ctaURLLinkTrackingOptedOut='" + ctaURLLinkTrackingOptedOut + '\'' +
+ ", qualityScore='" + qualityScore + '\'' +
+ ", createdAt=" + createdAt +
+ ", updatedAt=" + updatedAt +
+ '}';
+ }
+
+}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/SipResponseCode.java b/api/src/main/java/com/messagebird/objects/voicecalls/SipResponseCode.java
new file mode 100644
index 00000000..7061c8fe
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/SipResponseCode.java
@@ -0,0 +1,73 @@
+package com.messagebird.objects.voicecalls;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+
+/**
+ * More details, including additional descriptions and common caused can be found here: https://developers.messagebird.com/api/voice-calling/#sip-status-codes
+ * @author leandropinto
+ *
+ */
+public enum SipResponseCode {
+ //Successful
+ OK,
+ //The server understood the request, but is refusing to fulfill it.
+ FORBIDDEN,
+ //The server has definitive information that the user does not exist at the domain specified in the Request-URI.
+ NOT_FOUND,
+ //Couldn't find the user in time.
+ REQUEST_TIMEOUT,
+ //The user existed once, but is not available here any more.
+ GONE,
+ //Callee currently unavailable.
+ TEMPORARILY_UNAVAILABLE,
+ //Request-URI incomplete.
+ ADDRESS_INCOMPLETE,
+ //Callee is busy.
+ BUSY_HERE,
+ //Some aspect of the session description or the Request-URI is not acceptable.
+ NOT_ACCEPTABLE_HERE,
+ //The server could not fulfill the request due to some unexpected condition.
+ INTERNAL_SERVER_ERROR,
+ //The server does not have the ability to fulfill the request, such as because it does not recognize the request method.
+ NOT_IMPLEMENTED,
+ //The server is acting as a gateway or proxy, and received an invalid response from a downstream server while attempting to fulfill the request.
+ BAD_GATEWAY,
+ //The server is undergoing maintenance or is temporarily overloaded and so cannot process the request.
+ SERVICE_UNAVAILABLE;
+
+ @JsonCreator
+ public static SipResponseCode forValue(Integer value) {
+ switch (value) {
+ case 200:
+ return OK;
+ case 403:
+ return FORBIDDEN;
+ case 404:
+ return NOT_FOUND;
+ case 408:
+ return REQUEST_TIMEOUT;
+ case 410:
+ return GONE;
+ case 480:
+ return TEMPORARILY_UNAVAILABLE;
+ case 484:
+ return ADDRESS_INCOMPLETE;
+ case 486:
+ return BUSY_HERE;
+ case 488:
+ return NOT_ACCEPTABLE_HERE;
+ case 500:
+ return INTERNAL_SERVER_ERROR;
+ case 501:
+ return NOT_IMPLEMENTED;
+ case 502:
+ return BAD_GATEWAY;
+ case 503:
+ return SERVICE_UNAVAILABLE;
+
+ default:
+ throw new IllegalArgumentException("Unknown sip response code: " + value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/Transcription.java b/api/src/main/java/com/messagebird/objects/voicecalls/Transcription.java
index 3c6c665e..3a43a98a 100644
--- a/api/src/main/java/com/messagebird/objects/voicecalls/Transcription.java
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/Transcription.java
@@ -12,6 +12,8 @@ public class Transcription implements Serializable {
private String id;
private String recordingId;
private String error;
+ private String status;
+ private String legId;
private Date createdAt;
private Date updatedAt;
@JsonProperty("_links")
@@ -45,6 +47,10 @@ public Date getCreatedAt() {
return createdAt;
}
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
@@ -65,15 +71,33 @@ public void setLinks(Map links) {
this.links = links;
}
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getLegId() {
+ return legId;
+ }
+
+ public void setLegId(String legId) {
+ this.legId = legId;
+ }
+
@Override
public String toString() {
return "Transcription{" +
"id='" + id + '\'' +
", recordingId='" + recordingId + '\'' +
", error='" + error + '\'' +
+ ", status='" + status + '\'' +
+ ", legId='" + legId + '\'' +
", createdAt=" + createdAt +
", updatedAt=" + updatedAt +
- ", links='" + links + '\'' +
+ ", links=" + links +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/TranscriptionResponse.java b/api/src/main/java/com/messagebird/objects/voicecalls/TranscriptionResponse.java
index a760d915..442c44da 100644
--- a/api/src/main/java/com/messagebird/objects/voicecalls/TranscriptionResponse.java
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/TranscriptionResponse.java
@@ -1,13 +1,28 @@
package com.messagebird.objects.voicecalls;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
import java.io.Serializable;
import java.util.List;
+import java.util.Map;
public class TranscriptionResponse implements Serializable {
private static final long serialVersionUID = -25064223639161201L;
private List data;
+ @JsonProperty("_links")
+ private Map links;
+ private Pagination pagination;
+
+ public TranscriptionResponse() {}
+
+ public TranscriptionResponse(List data, Map links, Pagination pagination) {
+ this.data = data;
+ this.links = links;
+ this.pagination = pagination;
+ }
+
public List getData() {
return data;
}
@@ -16,10 +31,32 @@ public void setData(List data) {
this.data = data;
}
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public Map getLinks() {
+ return links;
+ }
+
+ public void setLinks(Map links) {
+ this.links = links;
+ }
+
+ public Pagination getPagination() {
+ return pagination;
+ }
+
+ public void setPagination(Pagination pagination) {
+ this.pagination = pagination;
+ }
+
@Override
public String toString() {
return "TranscriptionResponse{" +
"data=" + data +
+ ", links=" + links +
+ ", pagination=" + pagination +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java
index ea7bff21..573b42be 100644
--- a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java
@@ -1,5 +1,6 @@
package com.messagebird.objects.voicecalls;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.messagebird.objects.MessageBase;
import java.io.Serializable;
@@ -12,9 +13,7 @@ public class VoiceCall implements MessageBase, Serializable {
private String source;
private String destination;
private VoiceCallFlow callFlow;
-
- private String webhookUrl;
- private String webhookToken;
+ private Webhook webhook = new Webhook();
@Override
public String getBody() {
@@ -60,20 +59,43 @@ public void setCallFlow(VoiceCallFlow callFlow) {
this.callFlow = callFlow;
}
+ public Webhook getWebhook() {
+ return webhook;
+ }
+
+ @JsonIgnore
+ public void setWebhook(String url) {
+ this.setWebhook(url, null);
+ }
+
+ @JsonIgnore
+ public void setWebhook(String url, String token) {
+ this.webhook.setUrl(url);
+ this.webhook.setToken(token);
+ }
+
+ @JsonIgnore
+ @Deprecated
public String getWebhookUrl() {
- return webhookUrl;
+ return webhook.getUrl();
}
+ @JsonIgnore
+ @Deprecated
public void setWebhookUrl(String webhookUrl) {
- this.webhookUrl = webhookUrl;
+ this.webhook.setUrl(webhookUrl);
}
+ @JsonIgnore
+ @Deprecated
public String getWebhookToken() {
- return webhookToken;
+ return webhook.getToken();
}
+ @JsonIgnore
+ @Deprecated
public void setWebhookToken(String webhookToken) {
- this.webhookToken = webhookToken;
+ this.webhook.setToken(webhookToken);
}
@Override
@@ -82,8 +104,7 @@ public String toString() {
"source='" + source + '\'' +
", destination='" + destination + '\'' +
", callFlow=" + callFlow +
- ", webhookUrl='" + webhookUrl + '\'' +
- ", webhookToken='" + webhookToken + '\'' +
+ ", webhook=" + webhook +
'}';
}
}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallCondition.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallCondition.java
new file mode 100644
index 00000000..de99a1b9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallCondition.java
@@ -0,0 +1,34 @@
+package com.messagebird.objects.voicecalls;
+
+public class VoiceCallCondition {
+ private String variable;
+ private String operator;
+ private String value;
+
+ public VoiceCallCondition() {
+ }
+
+ public String getVariable() {
+ return variable;
+ }
+
+ public void setVariable(String variable) {
+ this.variable = variable;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public void setOperator(String operator) {
+ this.operator = operator;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java
index fc638cf6..53130c77 100644
--- a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java
@@ -1,10 +1,12 @@
package com.messagebird.objects.voicecalls;
import com.messagebird.objects.VoiceStep;
+import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
+import java.util.Map;
public class VoiceCallFlow implements Serializable {
@@ -14,10 +16,22 @@ public class VoiceCallFlow implements Serializable {
private String title;
private boolean record;
private List steps;
+
+ /*
+ * default is reserved name in JAVA so we use alternate name
+ */
+ @JsonProperty("default")
private boolean defaultCall;
+
+ @JsonProperty("maxDuration")
+ private Integer maxDuration;
+
private Date createdAt;
private Date updatedAt;
+ @JsonProperty("_links")
+ private Map links;
+
public String getId() {
return id;
}
@@ -26,10 +40,12 @@ public void setId(String id) {
this.id = id;
}
+ @Deprecated
public String getTitle() {
return title;
}
+ @Deprecated
public void setTitle(String title) {
this.title = title;
}
@@ -58,6 +74,10 @@ public void setDefaultCall(boolean defaultCall) {
this.defaultCall = defaultCall;
}
+ public Integer getMaxDuration() { return maxDuration; }
+
+ public void setMaxDuration(Integer maxDuration) { this.maxDuration = maxDuration; }
+
public Date getCreatedAt() {
return createdAt;
}
@@ -74,6 +94,14 @@ public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
+ public Map getLinks() {
+ return links;
+ }
+
+ public void setLinks(Map links) {
+ this.links = links;
+ }
+
@Override
public String toString() {
return "VoiceCallFlow{" +
@@ -81,7 +109,8 @@ public String toString() {
", title='" + title + '\'' +
", record=" + record +
", steps=" + steps +
- ", defaultCall=" + defaultCall +
+ ", default=" + defaultCall +
+ ", maxDuration=" + maxDuration +
", createdAt=" + createdAt +
", updatedAt=" + updatedAt +
'}';
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowList.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowList.java
new file mode 100644
index 00000000..dc2ad000
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowList.java
@@ -0,0 +1,63 @@
+package com.messagebird.objects.voicecalls;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a listing of VoiceCallFlow objects, along with pagination details.
+ * @TODO needs a little polishing (reorganise methods, rename properties, add
+ * missing properties)
+ */
+public class VoiceCallFlowList implements Serializable {
+
+ @JsonProperty("_links")
+ private Map links;
+
+ private Pagination pagination;
+
+ private List items;
+
+ @JsonCreator
+ public VoiceCallFlowList(@JsonProperty("data") List data) {
+ this.items = data;
+ }
+
+ @Override
+ public String toString() {
+ return pagination.toString();
+ }
+
+ public void setPagination(Pagination pagination) {
+ this.pagination = pagination;
+ }
+
+ public Integer getTotalCount() {
+ return this.pagination.getTotalCount();
+ }
+
+ public Integer getPageCount() {
+ return this.pagination.getPageCount();
+ }
+
+ public Integer getCurrentPage() {
+ return this.pagination.getCurrentPage();
+ }
+
+ public Integer getPerPage() {
+ return this.pagination.getPerPage();
+ }
+
+
+ public List getItems() {
+ return items;
+ }
+
+ public void setItems(List items) {
+ this.items = items;
+ }
+}
+
+
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowRequest.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowRequest.java
new file mode 100644
index 00000000..e447d9d9
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowRequest.java
@@ -0,0 +1,82 @@
+package com.messagebird.objects.voicecalls;
+
+import java.util.List;
+import java.util.Date;
+import com.messagebird.objects.*;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Contains writable values for VoiceCallFlow objects.
+ */
+public class VoiceCallFlowRequest {
+
+
+ private String id;
+ private String title;
+ private boolean record;
+ private List steps;
+
+ @JsonProperty("default")
+ private boolean defaultCall;
+
+ public VoiceCallFlowRequest(String id)
+ {
+ this.id = id;
+ }
+
+ public VoiceCallFlowRequest()
+ {
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Deprecated
+ public String getTitle() {
+ return title;
+ }
+
+ @Deprecated
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public boolean isRecord() {
+ return record;
+ }
+
+ public void setRecord(boolean record) {
+ this.record = record;
+ }
+
+ public List getSteps() {
+ return steps;
+ }
+
+ public void setSteps(List steps) {
+ this.steps = steps;
+ }
+
+ public boolean isDefaultCall() {
+ return defaultCall;
+ }
+
+ public void setDefaultCall(boolean defaultCall) {
+ this.defaultCall = defaultCall;
+ }
+
+ @Override
+ public String toString() {
+ return "VoiceCallFlowRequest{" +
+ "title='" + title + '\'' +
+ ", record=" + record +
+ ", steps=" + steps +
+ ", default=" + defaultCall +
+ '}';
+ }
+}
diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowResponse.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowResponse.java
new file mode 100644
index 00000000..ec4da8d0
--- /dev/null
+++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlowResponse.java
@@ -0,0 +1,40 @@
+package com.messagebird.objects.voicecalls;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+public class VoiceCallFlowResponse implements Serializable {
+
+ private static final long serialVersionUID = -3429781513863789117L;
+
+ private List data;
+ @JsonProperty("_links")
+ private Map