diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3d2ac0b..10f3091 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + ".": "0.2.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index ddb1fe8..1a193ff 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 183 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu/zavudev-5d75bbdcac3a0b0a8b798c0b4ef0dacfbc64ad4a20605489dc46dda7c8d1d8d8.yml -openapi_spec_hash: bb242cfd8cc43354412164c2dceae89c -config_hash: 261e1b852ca7f8364e4a283a3edd350a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu/zavudev-5257b1c4e3b9259ae2df6cd9ac2d2a31a39ddb336f50baf0dadbcc865c1913f3.yml +openapi_spec_hash: 4103decc37e4053c1cba58ba9527a5e7 +config_hash: f6a05e2edf2cd1af3f762b8ac759b9a7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ed7aac..a6fe92f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.2.0 (2026-09-15) + +Full Changelog: [v0.1.0...v0.2.0](https://github.com/zavudev/sdk-java/compare/v0.1.0...v0.2.0) + +### Features + +* **api:** api update ([39d685e](https://github.com/zavudev/sdk-java/commit/39d685ef84c834de2011a1109a517fc8403813a4)) +* **api:** api update ([b056ac9](https://github.com/zavudev/sdk-java/commit/b056ac941ed236586bda5182ebba8af9beedbba5)) +* **api:** api update ([dac47a9](https://github.com/zavudev/sdk-java/commit/dac47a994c60a797fa04af20a28e5a2f701903e9)) +* **api:** api update ([0624d56](https://github.com/zavudev/sdk-java/commit/0624d56475faaf8b95cf6a8d1b7578912ed701c1)) +* **api:** api update ([a9e59f9](https://github.com/zavudev/sdk-java/commit/a9e59f96118ea1f4356772648e51a8046cec2b8e)) + ## 0.1.0 (2026-09-08) Full Changelog: [v0.0.1...v0.1.0](https://github.com/zavudev/sdk-java/compare/v0.0.1...v0.1.0) diff --git a/README.md b/README.md index d80a923..0bb9a08 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.zavudev.api/zavudev-java)](https://central.sonatype.com/artifact/com.zavudev.api/zavudev-java/0.1.0) -[![javadoc](https://javadoc.io/badge2/com.zavudev.api/zavudev-java/javadoc.svg)](https://javadoc.io/doc/com.zavudev.api/zavudev-java/0.1.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.zavudev.api/zavudev-java)](https://central.sonatype.com/artifact/com.zavudev.api/zavudev-java/0.2.0) +[![javadoc](https://javadoc.io/badge2/com.zavudev.api/zavudev-java/javadoc.svg)](https://javadoc.io/doc/com.zavudev.api/zavudev-java/0.2.0) @@ -22,7 +22,7 @@ Use the Zavudev MCP Server to enable AI assistants to interact with this API, al -The REST API documentation can be found on [docs.zavu.dev](https://docs.zavu.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.zavudev.api/zavudev-java/0.1.0). +The REST API documentation can be found on [docs.zavu.dev](https://docs.zavu.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.zavudev.api/zavudev-java/0.2.0). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.zavu.dev](https://docs.zavu.dev ### Gradle ```kotlin -implementation("com.zavudev.api:zavudev-java:0.1.0") +implementation("com.zavudev.api:zavudev-java:0.2.0") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.zavudev.api:zavudev-java:0.1.0") com.zavudev.api zavudev-java - 0.1.0 + 0.2.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index eeed2ad..217e785 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.zavudev.api" - version = "0.1.0" // x-release-please-version + version = "0.2.0" // x-release-please-version } subprojects { diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressCreateParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressCreateParams.kt index e805e46..a761ba5 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressCreateParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressCreateParams.kt @@ -20,8 +20,8 @@ import java.util.Objects import java.util.Optional /** - * Create a regulatory address for phone number purchases. Some countries require a verified address - * before phone numbers can be activated. + * Create a regulatory address, to use as the value of an `address` requirement when buying a phone + * number. It is registered for review when it is created, with status `pending`. */ class AddressCreateParams private constructor( @@ -36,6 +36,22 @@ private constructor( */ fun countryCode(): String = body.countryCode() + /** + * First name of the person the address is registered to. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun firstName(): String = body.firstName() + + /** + * Last name of the person the address is registered to. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun lastName(): String = body.lastName() + /** * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -61,6 +77,8 @@ private constructor( fun administrativeArea(): Optional = body.administrativeArea() /** + * Business name, when the address belongs to a business. Defaults to the person's full name. + * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ @@ -73,23 +91,25 @@ private constructor( fun extendedAddress(): Optional = body.extendedAddress() /** - * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * Returns the raw JSON value of [countryCode]. + * + * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. */ - fun firstName(): Optional = body.firstName() + fun _countryCode(): JsonField = body._countryCode() /** - * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * Returns the raw JSON value of [firstName]. + * + * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected type. */ - fun lastName(): Optional = body.lastName() + fun _firstName(): JsonField = body._firstName() /** - * Returns the raw JSON value of [countryCode]. + * Returns the raw JSON value of [lastName]. * - * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected type. */ - fun _countryCode(): JsonField = body._countryCode() + fun _lastName(): JsonField = body._lastName() /** * Returns the raw JSON value of [locality]. @@ -134,20 +154,6 @@ private constructor( */ fun _extendedAddress(): JsonField = body._extendedAddress() - /** - * Returns the raw JSON value of [firstName]. - * - * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _firstName(): JsonField = body._firstName() - - /** - * Returns the raw JSON value of [lastName]. - * - * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _lastName(): JsonField = body._lastName() - fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ @@ -166,6 +172,8 @@ private constructor( * The following fields are required: * ```java * .countryCode() + * .firstName() + * .lastName() * .locality() * .postalCode() * .streetAddress() @@ -194,10 +202,10 @@ private constructor( * This is generally only useful if you are already constructing the body separately. * Otherwise, it's more convenient to use the top-level setters instead: * - [countryCode] + * - [firstName] + * - [lastName] * - [locality] * - [postalCode] - * - [streetAddress] - * - [administrativeArea] * - etc. */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -213,6 +221,29 @@ private constructor( */ fun countryCode(countryCode: JsonField) = apply { body.countryCode(countryCode) } + /** First name of the person the address is registered to. */ + fun firstName(firstName: String) = apply { body.firstName(firstName) } + + /** + * Sets [Builder.firstName] to an arbitrary JSON value. + * + * You should usually call [Builder.firstName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun firstName(firstName: JsonField) = apply { body.firstName(firstName) } + + /** Last name of the person the address is registered to. */ + fun lastName(lastName: String) = apply { body.lastName(lastName) } + + /** + * Sets [Builder.lastName] to an arbitrary JSON value. + * + * You should usually call [Builder.lastName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun lastName(lastName: JsonField) = apply { body.lastName(lastName) } + fun locality(locality: String) = apply { body.locality(locality) } /** @@ -262,6 +293,10 @@ private constructor( body.administrativeArea(administrativeArea) } + /** + * Business name, when the address belongs to a business. Defaults to the person's full + * name. + */ fun businessName(businessName: String) = apply { body.businessName(businessName) } /** @@ -290,27 +325,6 @@ private constructor( body.extendedAddress(extendedAddress) } - fun firstName(firstName: String) = apply { body.firstName(firstName) } - - /** - * Sets [Builder.firstName] to an arbitrary JSON value. - * - * You should usually call [Builder.firstName] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun firstName(firstName: JsonField) = apply { body.firstName(firstName) } - - fun lastName(lastName: String) = apply { body.lastName(lastName) } - - /** - * Sets [Builder.lastName] to an arbitrary JSON value. - * - * You should usually call [Builder.lastName] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun lastName(lastName: JsonField) = apply { body.lastName(lastName) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -436,6 +450,8 @@ private constructor( * The following fields are required: * ```java * .countryCode() + * .firstName() + * .lastName() * .locality() * .postalCode() * .streetAddress() @@ -457,18 +473,23 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams + /** + * A regulatory address. `firstName` and `lastName` are required: the carrier will not register + * an address without a named person. Requests that omit them are refused with `400 + * invalid_request`, and the SDKs still type them as optional until their next release. + */ class Body @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val countryCode: JsonField, + private val firstName: JsonField, + private val lastName: JsonField, private val locality: JsonField, private val postalCode: JsonField, private val streetAddress: JsonField, private val administrativeArea: JsonField, private val businessName: JsonField, private val extendedAddress: JsonField, - private val firstName: JsonField, - private val lastName: JsonField, private val additionalProperties: MutableMap, ) { @@ -477,6 +498,12 @@ private constructor( @JsonProperty("countryCode") @ExcludeMissing countryCode: JsonField = JsonMissing.of(), + @JsonProperty("firstName") + @ExcludeMissing + firstName: JsonField = JsonMissing.of(), + @JsonProperty("lastName") + @ExcludeMissing + lastName: JsonField = JsonMissing.of(), @JsonProperty("locality") @ExcludeMissing locality: JsonField = JsonMissing.of(), @@ -495,20 +522,16 @@ private constructor( @JsonProperty("extendedAddress") @ExcludeMissing extendedAddress: JsonField = JsonMissing.of(), - @JsonProperty("firstName") - @ExcludeMissing - firstName: JsonField = JsonMissing.of(), - @JsonProperty("lastName") @ExcludeMissing lastName: JsonField = JsonMissing.of(), ) : this( countryCode, + firstName, + lastName, locality, postalCode, streetAddress, administrativeArea, businessName, extendedAddress, - firstName, - lastName, mutableMapOf(), ) @@ -518,6 +541,22 @@ private constructor( */ fun countryCode(): String = countryCode.getRequired("countryCode") + /** + * First name of the person the address is registered to. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun firstName(): String = firstName.getRequired("firstName") + + /** + * Last name of the person the address is registered to. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun lastName(): String = lastName.getRequired("lastName") + /** * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -544,6 +583,9 @@ private constructor( administrativeArea.getOptional("administrativeArea") /** + * Business name, when the address belongs to a business. Defaults to the person's full + * name. + * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ @@ -556,25 +598,27 @@ private constructor( fun extendedAddress(): Optional = extendedAddress.getOptional("extendedAddress") /** - * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * Returns the raw JSON value of [countryCode]. + * + * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. */ - fun firstName(): Optional = firstName.getOptional("firstName") + @JsonProperty("countryCode") + @ExcludeMissing + fun _countryCode(): JsonField = countryCode /** - * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * Returns the raw JSON value of [firstName]. + * + * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected type. */ - fun lastName(): Optional = lastName.getOptional("lastName") + @JsonProperty("firstName") @ExcludeMissing fun _firstName(): JsonField = firstName /** - * Returns the raw JSON value of [countryCode]. + * Returns the raw JSON value of [lastName]. * - * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("countryCode") - @ExcludeMissing - fun _countryCode(): JsonField = countryCode + @JsonProperty("lastName") @ExcludeMissing fun _lastName(): JsonField = lastName /** * Returns the raw JSON value of [locality]. @@ -632,20 +676,6 @@ private constructor( @ExcludeMissing fun _extendedAddress(): JsonField = extendedAddress - /** - * Returns the raw JSON value of [firstName]. - * - * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("firstName") @ExcludeMissing fun _firstName(): JsonField = firstName - - /** - * Returns the raw JSON value of [lastName]. - * - * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("lastName") @ExcludeMissing fun _lastName(): JsonField = lastName - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -666,6 +696,8 @@ private constructor( * The following fields are required: * ```java * .countryCode() + * .firstName() + * .lastName() * .locality() * .postalCode() * .streetAddress() @@ -678,27 +710,27 @@ private constructor( class Builder internal constructor() { private var countryCode: JsonField? = null + private var firstName: JsonField? = null + private var lastName: JsonField? = null private var locality: JsonField? = null private var postalCode: JsonField? = null private var streetAddress: JsonField? = null private var administrativeArea: JsonField = JsonMissing.of() private var businessName: JsonField = JsonMissing.of() private var extendedAddress: JsonField = JsonMissing.of() - private var firstName: JsonField = JsonMissing.of() - private var lastName: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(body: Body) = apply { countryCode = body.countryCode + firstName = body.firstName + lastName = body.lastName locality = body.locality postalCode = body.postalCode streetAddress = body.streetAddress administrativeArea = body.administrativeArea businessName = body.businessName extendedAddress = body.extendedAddress - firstName = body.firstName - lastName = body.lastName additionalProperties = body.additionalProperties.toMutableMap() } @@ -715,6 +747,30 @@ private constructor( this.countryCode = countryCode } + /** First name of the person the address is registered to. */ + fun firstName(firstName: String) = firstName(JsonField.of(firstName)) + + /** + * Sets [Builder.firstName] to an arbitrary JSON value. + * + * You should usually call [Builder.firstName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun firstName(firstName: JsonField) = apply { this.firstName = firstName } + + /** Last name of the person the address is registered to. */ + fun lastName(lastName: String) = lastName(JsonField.of(lastName)) + + /** + * Sets [Builder.lastName] to an arbitrary JSON value. + * + * You should usually call [Builder.lastName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastName(lastName: JsonField) = apply { this.lastName = lastName } + fun locality(locality: String) = locality(JsonField.of(locality)) /** @@ -764,6 +820,10 @@ private constructor( this.administrativeArea = administrativeArea } + /** + * Business name, when the address belongs to a business. Defaults to the person's full + * name. + */ fun businessName(businessName: String) = businessName(JsonField.of(businessName)) /** @@ -791,28 +851,6 @@ private constructor( this.extendedAddress = extendedAddress } - fun firstName(firstName: String) = firstName(JsonField.of(firstName)) - - /** - * Sets [Builder.firstName] to an arbitrary JSON value. - * - * You should usually call [Builder.firstName] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun firstName(firstName: JsonField) = apply { this.firstName = firstName } - - fun lastName(lastName: String) = lastName(JsonField.of(lastName)) - - /** - * Sets [Builder.lastName] to an arbitrary JSON value. - * - * You should usually call [Builder.lastName] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun lastName(lastName: JsonField) = apply { this.lastName = lastName } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -840,6 +878,8 @@ private constructor( * The following fields are required: * ```java * .countryCode() + * .firstName() + * .lastName() * .locality() * .postalCode() * .streetAddress() @@ -850,14 +890,14 @@ private constructor( fun build(): Body = Body( checkRequired("countryCode", countryCode), + checkRequired("firstName", firstName), + checkRequired("lastName", lastName), checkRequired("locality", locality), checkRequired("postalCode", postalCode), checkRequired("streetAddress", streetAddress), administrativeArea, businessName, extendedAddress, - firstName, - lastName, additionalProperties.toMutableMap(), ) } @@ -879,14 +919,14 @@ private constructor( } countryCode() + firstName() + lastName() locality() postalCode() streetAddress() administrativeArea() businessName() extendedAddress() - firstName() - lastName() validated = true } @@ -907,14 +947,14 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (countryCode.asKnown().isPresent) 1 else 0) + + (if (firstName.asKnown().isPresent) 1 else 0) + + (if (lastName.asKnown().isPresent) 1 else 0) + (if (locality.asKnown().isPresent) 1 else 0) + (if (postalCode.asKnown().isPresent) 1 else 0) + (if (streetAddress.asKnown().isPresent) 1 else 0) + (if (administrativeArea.asKnown().isPresent) 1 else 0) + (if (businessName.asKnown().isPresent) 1 else 0) + - (if (extendedAddress.asKnown().isPresent) 1 else 0) + - (if (firstName.asKnown().isPresent) 1 else 0) + - (if (lastName.asKnown().isPresent) 1 else 0) + (if (extendedAddress.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -923,28 +963,28 @@ private constructor( return other is Body && countryCode == other.countryCode && + firstName == other.firstName && + lastName == other.lastName && locality == other.locality && postalCode == other.postalCode && streetAddress == other.streetAddress && administrativeArea == other.administrativeArea && businessName == other.businessName && extendedAddress == other.extendedAddress && - firstName == other.firstName && - lastName == other.lastName && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { Objects.hash( countryCode, + firstName, + lastName, locality, postalCode, streetAddress, administrativeArea, businessName, extendedAddress, - firstName, - lastName, additionalProperties, ) } @@ -952,7 +992,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Body{countryCode=$countryCode, locality=$locality, postalCode=$postalCode, streetAddress=$streetAddress, administrativeArea=$administrativeArea, businessName=$businessName, extendedAddress=$extendedAddress, firstName=$firstName, lastName=$lastName, additionalProperties=$additionalProperties}" + "Body{countryCode=$countryCode, firstName=$firstName, lastName=$lastName, locality=$locality, postalCode=$postalCode, streetAddress=$streetAddress, administrativeArea=$administrativeArea, businessName=$businessName, extendedAddress=$extendedAddress, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressDeleteParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressDeleteParams.kt index 3941a47..919a758 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressDeleteParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/addresses/AddressDeleteParams.kt @@ -11,7 +11,11 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** Delete a regulatory address. Cannot delete addresses that are in use. */ +/** + * Delete a regulatory address from this project. Any address can be deleted, whatever its status. + * Phone numbers already purchased with it are not affected, and neither is information already + * submitted for later purchases in its country. + */ class AddressDeleteParams private constructor( private val addressId: String?, diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrand.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrand.kt index 5df6461..52de4ed 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrand.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrand.kt @@ -42,6 +42,7 @@ private constructor( private val ein: JsonField, private val failureReason: JsonField, private val firstName: JsonField, + private val identityStatus: JsonField, private val lastName: JsonField, private val stockExchange: JsonField, private val stockSymbol: JsonField, @@ -89,6 +90,9 @@ private constructor( @ExcludeMissing failureReason: JsonField = JsonMissing.of(), @JsonProperty("firstName") @ExcludeMissing firstName: JsonField = JsonMissing.of(), + @JsonProperty("identityStatus") + @ExcludeMissing + identityStatus: JsonField = JsonMissing.of(), @JsonProperty("lastName") @ExcludeMissing lastName: JsonField = JsonMissing.of(), @JsonProperty("stockExchange") @ExcludeMissing @@ -124,6 +128,7 @@ private constructor( ein, failureReason, firstName, + identityStatus, lastName, stockExchange, stockSymbol, @@ -203,6 +208,14 @@ private constructor( /** * Status of a 10DLC brand registration. + * - `draft`: created, not yet submitted to the carrier. + * - `pending`: submitted, awaiting the carrier's answer. + * - `verified`: the carrier registered the brand AND verified the business behind it. + * - `unverified`: the carrier registered the brand but did not verify the business — the + * registration exists, the identity check did not pass or has not been resolved. Campaigns + * are allowed, with lower daily limits. Read `identityStatus` for the carrier's own wording. + * - `rejected`: refused by the carrier. + * - `failed`: the registration never reached the carrier; the fee is refunded. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -273,6 +286,17 @@ private constructor( */ fun firstName(): Optional = firstName.getOptional("firstName") + /** + * The carrier's raw identity verdict on the business, as the carrier spells it (`VERIFIED`, + * `VETTED_VERIFIED`, `SELF_DECLARED`, `UNVERIFIED`). Null while the identity has not been + * resolved — which is not the same as verified, and is why such a brand reports `status: + * unverified`. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun identityStatus(): Optional = identityStatus.getOptional("identityStatus") + /** * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -460,6 +484,15 @@ private constructor( */ @JsonProperty("firstName") @ExcludeMissing fun _firstName(): JsonField = firstName + /** + * Returns the raw JSON value of [identityStatus]. + * + * Unlike [identityStatus], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("identityStatus") + @ExcludeMissing + fun _identityStatus(): JsonField = identityStatus + /** * Returns the raw JSON value of [lastName]. * @@ -569,6 +602,7 @@ private constructor( private var ein: JsonField = JsonMissing.of() private var failureReason: JsonField = JsonMissing.of() private var firstName: JsonField = JsonMissing.of() + private var identityStatus: JsonField = JsonMissing.of() private var lastName: JsonField = JsonMissing.of() private var stockExchange: JsonField = JsonMissing.of() private var stockSymbol: JsonField = JsonMissing.of() @@ -599,6 +633,7 @@ private constructor( ein = tenDlcBrand.ein failureReason = tenDlcBrand.failureReason firstName = tenDlcBrand.firstName + identityStatus = tenDlcBrand.identityStatus lastName = tenDlcBrand.lastName stockExchange = tenDlcBrand.stockExchange stockSymbol = tenDlcBrand.stockSymbol @@ -716,7 +751,18 @@ private constructor( */ fun state(state: JsonField) = apply { this.state = state } - /** Status of a 10DLC brand registration. */ + /** + * Status of a 10DLC brand registration. + * - `draft`: created, not yet submitted to the carrier. + * - `pending`: submitted, awaiting the carrier's answer. + * - `verified`: the carrier registered the brand AND verified the business behind it. + * - `unverified`: the carrier registered the brand but did not verify the business — the + * registration exists, the identity check did not pass or has not been resolved. + * Campaigns are allowed, with lower daily limits. Read `identityStatus` for the carrier's + * own wording. + * - `rejected`: refused by the carrier. + * - `failed`: the registration never reached the carrier; the fee is refunded. + */ fun status(status: Status) = status(JsonField.of(status)) /** @@ -860,6 +906,30 @@ private constructor( */ fun firstName(firstName: JsonField) = apply { this.firstName = firstName } + /** + * The carrier's raw identity verdict on the business, as the carrier spells it (`VERIFIED`, + * `VETTED_VERIFIED`, `SELF_DECLARED`, `UNVERIFIED`). Null while the identity has not been + * resolved — which is not the same as verified, and is why such a brand reports `status: + * unverified`. + */ + fun identityStatus(identityStatus: String?) = + identityStatus(JsonField.ofNullable(identityStatus)) + + /** Alias for calling [Builder.identityStatus] with `identityStatus.orElse(null)`. */ + fun identityStatus(identityStatus: Optional) = + identityStatus(identityStatus.getOrNull()) + + /** + * Sets [Builder.identityStatus] to an arbitrary JSON value. + * + * You should usually call [Builder.identityStatus] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun identityStatus(identityStatus: JsonField) = apply { + this.identityStatus = identityStatus + } + fun lastName(lastName: String?) = lastName(JsonField.ofNullable(lastName)) /** Alias for calling [Builder.lastName] with `lastName.orElse(null)`. */ @@ -1018,6 +1088,7 @@ private constructor( ein, failureReason, firstName, + identityStatus, lastName, stockExchange, stockSymbol, @@ -1063,6 +1134,7 @@ private constructor( ein() failureReason() firstName() + identityStatus() lastName() stockExchange() stockSymbol() @@ -1107,6 +1179,7 @@ private constructor( (if (ein.asKnown().isPresent) 1 else 0) + (if (failureReason.asKnown().isPresent) 1 else 0) + (if (firstName.asKnown().isPresent) 1 else 0) + + (if (identityStatus.asKnown().isPresent) 1 else 0) + (if (lastName.asKnown().isPresent) 1 else 0) + (if (stockExchange.asKnown().isPresent) 1 else 0) + (if (stockSymbol.asKnown().isPresent) 1 else 0) + @@ -1269,7 +1342,17 @@ private constructor( override fun toString() = value.toString() } - /** Status of a 10DLC brand registration. */ + /** + * Status of a 10DLC brand registration. + * - `draft`: created, not yet submitted to the carrier. + * - `pending`: submitted, awaiting the carrier's answer. + * - `verified`: the carrier registered the brand AND verified the business behind it. + * - `unverified`: the carrier registered the brand but did not verify the business — the + * registration exists, the identity check did not pass or has not been resolved. Campaigns + * are allowed, with lower daily limits. Read `identityStatus` for the carrier's own wording. + * - `rejected`: refused by the carrier. + * - `failed`: the registration never reached the carrier; the fee is refunded. + */ class Status @JsonCreator private constructor(private val value: JsonField) : Enum { /** @@ -1290,8 +1373,12 @@ private constructor( @JvmField val VERIFIED = of("verified") + @JvmField val UNVERIFIED = of("unverified") + @JvmField val REJECTED = of("rejected") + @JvmField val FAILED = of("failed") + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) } @@ -1300,7 +1387,9 @@ private constructor( DRAFT, PENDING, VERIFIED, + UNVERIFIED, REJECTED, + FAILED, } /** @@ -1316,7 +1405,9 @@ private constructor( DRAFT, PENDING, VERIFIED, + UNVERIFIED, REJECTED, + FAILED, /** An enum member indicating that [Status] was instantiated with an unknown value. */ _UNKNOWN, } @@ -1333,7 +1424,9 @@ private constructor( DRAFT -> Value.DRAFT PENDING -> Value.PENDING VERIFIED -> Value.VERIFIED + UNVERIFIED -> Value.UNVERIFIED REJECTED -> Value.REJECTED + FAILED -> Value.FAILED else -> Value._UNKNOWN } @@ -1351,7 +1444,9 @@ private constructor( DRAFT -> Known.DRAFT PENDING -> Known.PENDING VERIFIED -> Known.VERIFIED + UNVERIFIED -> Known.UNVERIFIED REJECTED -> Known.REJECTED + FAILED -> Known.FAILED else -> throw ZavudevInvalidDataException("Unknown Status: $value") } @@ -1442,6 +1537,7 @@ private constructor( ein == other.ein && failureReason == other.failureReason && firstName == other.firstName && + identityStatus == other.identityStatus && lastName == other.lastName && stockExchange == other.stockExchange && stockSymbol == other.stockSymbol && @@ -1473,6 +1569,7 @@ private constructor( ein, failureReason, firstName, + identityStatus, lastName, stockExchange, stockSymbol, @@ -1486,5 +1583,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "TenDlcBrand{id=$id, city=$city, country=$country, createdAt=$createdAt, displayName=$displayName, email=$email, entityType=$entityType, phone=$phone, postalCode=$postalCode, state=$state, status=$status, street=$street, updatedAt=$updatedAt, vertical=$vertical, brandRelationship=$brandRelationship, brandScore=$brandScore, companyName=$companyName, ein=$ein, failureReason=$failureReason, firstName=$firstName, lastName=$lastName, stockExchange=$stockExchange, stockSymbol=$stockSymbol, submittedAt=$submittedAt, verifiedAt=$verifiedAt, website=$website, additionalProperties=$additionalProperties}" + "TenDlcBrand{id=$id, city=$city, country=$country, createdAt=$createdAt, displayName=$displayName, email=$email, entityType=$entityType, phone=$phone, postalCode=$postalCode, state=$state, status=$status, street=$street, updatedAt=$updatedAt, vertical=$vertical, brandRelationship=$brandRelationship, brandScore=$brandScore, companyName=$companyName, ein=$ein, failureReason=$failureReason, firstName=$firstName, identityStatus=$identityStatus, lastName=$lastName, stockExchange=$stockExchange, stockSymbol=$stockSymbol, submittedAt=$submittedAt, verifiedAt=$verifiedAt, website=$website, additionalProperties=$additionalProperties}" } diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumber.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumber.kt index 2b4f3db..51f4573 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumber.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumber.kt @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.zavudev.api.core.Enum import com.zavudev.api.core.ExcludeMissing import com.zavudev.api.core.JsonField import com.zavudev.api.core.JsonMissing @@ -28,6 +29,7 @@ private constructor( private val createdAt: JsonField, private val phoneNumber: JsonField, private val pricing: JsonField, + private val regulatoryStatus: JsonField, private val status: JsonField, private val name: JsonField, private val nextRenewalDate: JsonField, @@ -51,6 +53,9 @@ private constructor( @JsonProperty("pricing") @ExcludeMissing pricing: JsonField = JsonMissing.of(), + @JsonProperty("regulatoryStatus") + @ExcludeMissing + regulatoryStatus: JsonField = JsonMissing.of(), @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), @@ -68,6 +73,7 @@ private constructor( createdAt, phoneNumber, pricing, + regulatoryStatus, status, name, nextRenewalDate, @@ -107,6 +113,28 @@ private constructor( fun pricing(): OwnedPhoneNumberPricing = pricing.getRequired("pricing") /** + * Regulatory review state. Numbers that need no review are `approved` immediately. A number + * bought with regulatory information is owned and billed from purchase and starts + * `pending_review`; it cannot send messages or place calls until this is `approved`. The state + * is re-checked every 6 hours: poll `GET /v1/phone-numbers/{phoneNumberId}` to follow it. + * + * Assign it to a sender with `PATCH /v1/phone-numbers/{phoneNumberId}` (`senderId`) before or + * after approval. A number assigned while under review is recorded and connected to that sender + * when it is approved; the connection is retried until it succeeds. A sender created over the + * API is set up for SMS as part of the assignment. `rejected` means review refused the + * information: the number cannot be assigned to a sender. A number that stays `pending_review` + * may be waiting on information the API cannot supply; contact support. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun regulatoryStatus(): RegulatoryStatus = regulatoryStatus.getRequired("regulatoryStatus") + + /** + * Billing state of an owned number, separate from `regulatoryStatus`. `pending` is legacy and + * is not written to numbers today. The SDKs carry `active`, `suspended` and `pending` only; + * `releasing` and `released` are returned by the REST API until their next release. + * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ @@ -181,6 +209,16 @@ private constructor( @ExcludeMissing fun _pricing(): JsonField = pricing + /** + * Returns the raw JSON value of [regulatoryStatus]. + * + * Unlike [regulatoryStatus], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("regulatoryStatus") + @ExcludeMissing + fun _regulatoryStatus(): JsonField = regulatoryStatus + /** * Returns the raw JSON value of [status]. * @@ -244,6 +282,7 @@ private constructor( * .createdAt() * .phoneNumber() * .pricing() + * .regulatoryStatus() * .status() * ``` */ @@ -258,6 +297,7 @@ private constructor( private var createdAt: JsonField? = null private var phoneNumber: JsonField? = null private var pricing: JsonField? = null + private var regulatoryStatus: JsonField? = null private var status: JsonField? = null private var name: JsonField = JsonMissing.of() private var nextRenewalDate: JsonField = JsonMissing.of() @@ -272,6 +312,7 @@ private constructor( createdAt = ownedPhoneNumber.createdAt phoneNumber = ownedPhoneNumber.phoneNumber pricing = ownedPhoneNumber.pricing + regulatoryStatus = ownedPhoneNumber.regulatoryStatus status = ownedPhoneNumber.status name = ownedPhoneNumber.name nextRenewalDate = ownedPhoneNumber.nextRenewalDate @@ -348,6 +389,39 @@ private constructor( */ fun pricing(pricing: JsonField) = apply { this.pricing = pricing } + /** + * Regulatory review state. Numbers that need no review are `approved` immediately. A number + * bought with regulatory information is owned and billed from purchase and starts + * `pending_review`; it cannot send messages or place calls until this is `approved`. The + * state is re-checked every 6 hours: poll `GET /v1/phone-numbers/{phoneNumberId}` to follow + * it. + * + * Assign it to a sender with `PATCH /v1/phone-numbers/{phoneNumberId}` (`senderId`) before + * or after approval. A number assigned while under review is recorded and connected to that + * sender when it is approved; the connection is retried until it succeeds. A sender created + * over the API is set up for SMS as part of the assignment. `rejected` means review refused + * the information: the number cannot be assigned to a sender. A number that stays + * `pending_review` may be waiting on information the API cannot supply; contact support. + */ + fun regulatoryStatus(regulatoryStatus: RegulatoryStatus) = + regulatoryStatus(JsonField.of(regulatoryStatus)) + + /** + * Sets [Builder.regulatoryStatus] to an arbitrary JSON value. + * + * You should usually call [Builder.regulatoryStatus] with a well-typed [RegulatoryStatus] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun regulatoryStatus(regulatoryStatus: JsonField) = apply { + this.regulatoryStatus = regulatoryStatus + } + + /** + * Billing state of an owned number, separate from `regulatoryStatus`. `pending` is legacy + * and is not written to numbers today. The SDKs carry `active`, `suspended` and `pending` + * only; `releasing` and `released` are returned by the REST API until their next release. + */ fun status(status: PhoneNumberStatus) = status(JsonField.of(status)) /** @@ -437,6 +511,7 @@ private constructor( * .createdAt() * .phoneNumber() * .pricing() + * .regulatoryStatus() * .status() * ``` * @@ -449,6 +524,7 @@ private constructor( checkRequired("createdAt", createdAt), checkRequired("phoneNumber", phoneNumber), checkRequired("pricing", pricing), + checkRequired("regulatoryStatus", regulatoryStatus), checkRequired("status", status), name, nextRenewalDate, @@ -478,6 +554,7 @@ private constructor( createdAt() phoneNumber() pricing().validate() + regulatoryStatus().validate() status().validate() name() nextRenewalDate() @@ -506,12 +583,170 @@ private constructor( (if (createdAt.asKnown().isPresent) 1 else 0) + (if (phoneNumber.asKnown().isPresent) 1 else 0) + (pricing.asKnown().getOrNull()?.validity() ?: 0) + + (regulatoryStatus.asKnown().getOrNull()?.validity() ?: 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + (if (name.asKnown().isPresent) 1 else 0) + (if (nextRenewalDate.asKnown().isPresent) 1 else 0) + (if (senderId.asKnown().isPresent) 1 else 0) + (if (updatedAt.asKnown().isPresent) 1 else 0) + /** + * Regulatory review state. Numbers that need no review are `approved` immediately. A number + * bought with regulatory information is owned and billed from purchase and starts + * `pending_review`; it cannot send messages or place calls until this is `approved`. The state + * is re-checked every 6 hours: poll `GET /v1/phone-numbers/{phoneNumberId}` to follow it. + * + * Assign it to a sender with `PATCH /v1/phone-numbers/{phoneNumberId}` (`senderId`) before or + * after approval. A number assigned while under review is recorded and connected to that sender + * when it is approved; the connection is retried until it succeeds. A sender created over the + * API is set up for SMS as part of the assignment. `rejected` means review refused the + * information: the number cannot be assigned to a sender. A number that stays `pending_review` + * may be waiting on information the API cannot supply; contact support. + */ + class RegulatoryStatus @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val APPROVED = of("approved") + + @JvmField val PENDING_REVIEW = of("pending_review") + + @JvmField val REJECTED = of("rejected") + + @JvmStatic fun of(value: String) = RegulatoryStatus(JsonField.of(value)) + } + + /** An enum containing [RegulatoryStatus]'s known values. */ + enum class Known { + APPROVED, + PENDING_REVIEW, + REJECTED, + } + + /** + * An enum containing [RegulatoryStatus]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [RegulatoryStatus] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + APPROVED, + PENDING_REVIEW, + REJECTED, + /** + * An enum member indicating that [RegulatoryStatus] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + APPROVED -> Value.APPROVED + PENDING_REVIEW -> Value.PENDING_REVIEW + REJECTED -> Value.REJECTED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws ZavudevInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + APPROVED -> Known.APPROVED + PENDING_REVIEW -> Known.PENDING_REVIEW + REJECTED -> Known.REJECTED + else -> throw ZavudevInvalidDataException("Unknown RegulatoryStatus: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws ZavudevInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { ZavudevInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws ZavudevInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): RegulatoryStatus = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: ZavudevInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RegulatoryStatus && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -523,6 +758,7 @@ private constructor( createdAt == other.createdAt && phoneNumber == other.phoneNumber && pricing == other.pricing && + regulatoryStatus == other.regulatoryStatus && status == other.status && name == other.name && nextRenewalDate == other.nextRenewalDate && @@ -538,6 +774,7 @@ private constructor( createdAt, phoneNumber, pricing, + regulatoryStatus, status, name, nextRenewalDate, @@ -550,5 +787,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "OwnedPhoneNumber{id=$id, capabilities=$capabilities, createdAt=$createdAt, phoneNumber=$phoneNumber, pricing=$pricing, status=$status, name=$name, nextRenewalDate=$nextRenewalDate, senderId=$senderId, updatedAt=$updatedAt, additionalProperties=$additionalProperties}" + "OwnedPhoneNumber{id=$id, capabilities=$capabilities, createdAt=$createdAt, phoneNumber=$phoneNumber, pricing=$pricing, regulatoryStatus=$regulatoryStatus, status=$status, name=$name, nextRenewalDate=$nextRenewalDate, senderId=$senderId, updatedAt=$updatedAt, additionalProperties=$additionalProperties}" } diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPricing.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPricing.kt index 70cf9c1..5599759 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPricing.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPricing.kt @@ -38,9 +38,9 @@ private constructor( ) : this(isFreeEligible, monthlyPrice, upfrontPrice, mutableMapOf()) /** - * Whether this number qualifies as the plan-included US number on paid plans. The benefit is - * one per account: it is never offered again once claimed, not even after the number is - * released. + * Whether this number qualifies as the plan-included number: a US or Canadian number (a +1 + * number) costing $20 a month or less. The benefit is one per account: it is never offered + * again once claimed, not even after the number is released. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -125,9 +125,9 @@ private constructor( } /** - * Whether this number qualifies as the plan-included US number on paid plans. The benefit - * is one per account: it is never offered again once claimed, not even after the number is - * released. + * Whether this number qualifies as the plan-included number: a US or Canadian number (a +1 + * number) costing $20 a month or less. The benefit is one per account: it is never offered + * again once claimed, not even after the number is released. */ fun isFreeEligible(isFreeEligible: Boolean) = isFreeEligible(JsonField.of(isFreeEligible)) diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParams.kt index 205e4dc..d6119ea 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParams.kt @@ -11,20 +11,50 @@ import com.zavudev.api.core.JsonField import com.zavudev.api.core.JsonMissing import com.zavudev.api.core.JsonValue import com.zavudev.api.core.Params +import com.zavudev.api.core.checkKnown import com.zavudev.api.core.checkRequired import com.zavudev.api.core.http.Headers import com.zavudev.api.core.http.QueryParams +import com.zavudev.api.core.toImmutable import com.zavudev.api.errors.ZavudevInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Purchase an available phone number. Requires a paid plan: the Free plan cannot purchase phone - * numbers and receives `402` with code `paid_plan_required`. Paid plans include one US number at no - * charge. The included number is one per account and is granted once: claiming it spends the - * benefit for good, so releasing that number does not make another one free, and numbers the - * account already bought do not consume it. + * numbers and receives `402` with code `paid_plan_required`. + * + * **The included number.** A paid plan includes one number at no charge, once per account: it must + * be a US or Canadian number (a +1 number) costing $20 a month or less. `isFreeEligible` in `GET + * /v1/phone-numbers/available` marks the numbers that qualify. Claiming it spends the benefit for + * good, across every team the account owner owns, so releasing that number does not make another + * one free. + * + * **Numbers with regulatory requirements.** Which numbers need regulatory information is decided + * per number, not by a fixed country list. The purchase looks the requirements up for the exact + * number before charging anything: + * 1. `GET /v1/phone-numbers/requirements?phoneNumber=...`. If `items` is empty, buy normally. + * 2. Create what it asks for: addresses with `POST /v1/addresses`, documents with `POST + * /v1/documents`. + * 3. Purchase with `type` and `regulatoryRequirements`. The number is bought and billed at once + * with `regulatoryStatus: pending_review`. + * 4. Poll `GET /v1/phone-numbers/{phoneNumberId}` until `regulatoryStatus` is `approved`. Assign it + * to a sender before or after approval; it starts carrying messages once approved. + * + * **Reuse.** Information you submitted is kept for your project, per country and `type`, and a + * later purchase there may omit `regulatoryRequirements`. Reuse only happens when what is kept + * still covers every requirement of the new number and every address and document in it belongs to + * the project. Otherwise, or when nothing is kept, the purchase returns `400 + * regulatory_compliance_required` with the missing requirements in `details`. + * + * Invalid values (a missing, unknown or repeated requirement id, an address or document from + * another project, or one rejected in review) return `400 invalid_request`. If an address or + * document cannot be registered for review, the purchase returns `400 invalid_request` naming the + * requirement. If the requirements cannot be looked up, the purchase returns `502 + * requirements_unavailable`, except for US and Canadian numbers, which are sold as numbers without + * requirements. None of these errors charge anything. */ class PhoneNumberPurchaseParams private constructor( @@ -49,6 +79,33 @@ private constructor( */ fun name(): Optional = body.name() + /** + * Regulatory information, for numbers whose requirements list is not empty. Get the list with + * `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one entry per requirement id, + * except `action` requirements, which take no value. Every required id must be present, once, + * and no unknown id may be sent; otherwise the purchase is refused with `400 invalid_request` + * before anything is charged. + * + * The information is kept for your project under the number's country and `type`. A later + * purchase there may omit this field if what is kept still covers that number's requirements. + * Omit it for numbers without requirements. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun regulatoryRequirements(): Optional> = + body.regulatoryRequirements() + + /** + * Type of phone number. `mobile` is stocked in countries where no geographic (`local`) or + * non-geographic (`national`) inventory exists, and in several markets it is the only type that + * can receive SMS. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = body.type() + /** * Returns the raw JSON value of [phoneNumber]. * @@ -63,6 +120,22 @@ private constructor( */ fun _name(): JsonField = body._name() + /** + * Returns the raw JSON value of [regulatoryRequirements]. + * + * Unlike [regulatoryRequirements], this method doesn't throw if the JSON field has an + * unexpected type. + */ + fun _regulatoryRequirements(): JsonField> = + body._regulatoryRequirements() + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _type(): JsonField = body._type() + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ @@ -107,6 +180,8 @@ private constructor( * Otherwise, it's more convenient to use the top-level setters instead: * - [phoneNumber] * - [name] + * - [regulatoryRequirements] + * - [type] */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -133,6 +208,58 @@ private constructor( */ fun name(name: JsonField) = apply { body.name(name) } + /** + * Regulatory information, for numbers whose requirements list is not empty. Get the list + * with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one entry per + * requirement id, except `action` requirements, which take no value. Every required id must + * be present, once, and no unknown id may be sent; otherwise the purchase is refused with + * `400 invalid_request` before anything is charged. + * + * The information is kept for your project under the number's country and `type`. A later + * purchase there may omit this field if what is kept still covers that number's + * requirements. Omit it for numbers without requirements. + */ + fun regulatoryRequirements(regulatoryRequirements: List) = apply { + body.regulatoryRequirements(regulatoryRequirements) + } + + /** + * Sets [Builder.regulatoryRequirements] to an arbitrary JSON value. + * + * You should usually call [Builder.regulatoryRequirements] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun regulatoryRequirements(regulatoryRequirements: JsonField>) = + apply { + body.regulatoryRequirements(regulatoryRequirements) + } + + /** + * Adds a single [RegulatoryRequirement] to [regulatoryRequirements]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRegulatoryRequirement(regulatoryRequirement: RegulatoryRequirement) = apply { + body.addRegulatoryRequirement(regulatoryRequirement) + } + + /** + * Type of phone number. `mobile` is stocked in countries where no geographic (`local`) or + * non-geographic (`national`) inventory exists, and in several markets it is the only type + * that can receive SMS. + */ + fun type(type: PhoneNumberType) = apply { body.type(type) } + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [PhoneNumberType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { body.type(type) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -281,6 +408,8 @@ private constructor( private constructor( private val phoneNumber: JsonField, private val name: JsonField, + private val regulatoryRequirements: JsonField>, + private val type: JsonField, private val additionalProperties: MutableMap, ) { @@ -290,7 +419,13 @@ private constructor( @ExcludeMissing phoneNumber: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - ) : this(phoneNumber, name, mutableMapOf()) + @JsonProperty("regulatoryRequirements") + @ExcludeMissing + regulatoryRequirements: JsonField> = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(phoneNumber, name, regulatoryRequirements, type, mutableMapOf()) /** * Phone number in E.164 format. @@ -308,6 +443,33 @@ private constructor( */ fun name(): Optional = name.getOptional("name") + /** + * Regulatory information, for numbers whose requirements list is not empty. Get the list + * with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one entry per + * requirement id, except `action` requirements, which take no value. Every required id must + * be present, once, and no unknown id may be sent; otherwise the purchase is refused with + * `400 invalid_request` before anything is charged. + * + * The information is kept for your project under the number's country and `type`. A later + * purchase there may omit this field if what is kept still covers that number's + * requirements. Omit it for numbers without requirements. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun regulatoryRequirements(): Optional> = + regulatoryRequirements.getOptional("regulatoryRequirements") + + /** + * Type of phone number. `mobile` is stocked in countries where no geographic (`local`) or + * non-geographic (`national`) inventory exists, and in several markets it is the only type + * that can receive SMS. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + /** * Returns the raw JSON value of [phoneNumber]. * @@ -324,6 +486,24 @@ private constructor( */ @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** + * Returns the raw JSON value of [regulatoryRequirements]. + * + * Unlike [regulatoryRequirements], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("regulatoryRequirements") + @ExcludeMissing + fun _regulatoryRequirements(): JsonField> = + regulatoryRequirements + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -354,12 +534,17 @@ private constructor( private var phoneNumber: JsonField? = null private var name: JsonField = JsonMissing.of() + private var regulatoryRequirements: JsonField>? = + null + private var type: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(body: Body) = apply { phoneNumber = body.phoneNumber name = body.name + regulatoryRequirements = body.regulatoryRequirements.map { it.toMutableList() } + type = body.type additionalProperties = body.additionalProperties.toMutableMap() } @@ -389,6 +574,61 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** + * Regulatory information, for numbers whose requirements list is not empty. Get the + * list with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one entry per + * requirement id, except `action` requirements, which take no value. Every required id + * must be present, once, and no unknown id may be sent; otherwise the purchase is + * refused with `400 invalid_request` before anything is charged. + * + * The information is kept for your project under the number's country and `type`. A + * later purchase there may omit this field if what is kept still covers that number's + * requirements. Omit it for numbers without requirements. + */ + fun regulatoryRequirements(regulatoryRequirements: List) = + regulatoryRequirements(JsonField.of(regulatoryRequirements)) + + /** + * Sets [Builder.regulatoryRequirements] to an arbitrary JSON value. + * + * You should usually call [Builder.regulatoryRequirements] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun regulatoryRequirements( + regulatoryRequirements: JsonField> + ) = apply { + this.regulatoryRequirements = regulatoryRequirements.map { it.toMutableList() } + } + + /** + * Adds a single [RegulatoryRequirement] to [regulatoryRequirements]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRegulatoryRequirement(regulatoryRequirement: RegulatoryRequirement) = apply { + regulatoryRequirements = + (regulatoryRequirements ?: JsonField.of(mutableListOf())).also { + checkKnown("regulatoryRequirements", it).add(regulatoryRequirement) + } + } + + /** + * Type of phone number. `mobile` is stocked in countries where no geographic (`local`) + * or non-geographic (`national`) inventory exists, and in several markets it is the + * only type that can receive SMS. + */ + fun type(type: PhoneNumberType) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [PhoneNumberType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -424,6 +664,8 @@ private constructor( Body( checkRequired("phoneNumber", phoneNumber), name, + (regulatoryRequirements ?: JsonMissing.of()).map { it.toImmutable() }, + type, additionalProperties.toMutableMap(), ) } @@ -446,6 +688,8 @@ private constructor( phoneNumber() name() + regulatoryRequirements().ifPresent { it.forEach { it.validate() } } + type().ifPresent { it.validate() } validated = true } @@ -466,7 +710,10 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (phoneNumber.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + + (regulatoryRequirements.asKnown().getOrNull()?.sumOf { it.validity().toInt() } + ?: 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -476,15 +723,252 @@ private constructor( return other is Body && phoneNumber == other.phoneNumber && name == other.name && + regulatoryRequirements == other.regulatoryRequirements && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(phoneNumber, name, regulatoryRequirements, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{phoneNumber=$phoneNumber, name=$name, regulatoryRequirements=$regulatoryRequirements, type=$type, additionalProperties=$additionalProperties}" + } + + class RegulatoryRequirement + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val fieldValue: JsonField, + private val requirementType: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("fieldValue") + @ExcludeMissing + fieldValue: JsonField = JsonMissing.of(), + @JsonProperty("requirementType") + @ExcludeMissing + requirementType: JsonField = JsonMissing.of(), + ) : this(fieldValue, requirementType, mutableMapOf()) + + /** + * Depends on the requirement's `type`: the text itself for `textual`; for `address`, the + * `id` of an address created in this project with `POST /v1/addresses`; for `document`, the + * `id` of a document created with `POST /v1/documents`. An address or document from another + * project, or one rejected in review, is refused. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun fieldValue(): String = fieldValue.getRequired("fieldValue") + + /** + * A `requirementTypes[].id` from `GET /v1/phone-numbers/requirements`. Each id may appear + * only once. + * + * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun requirementType(): String = requirementType.getRequired("requirementType") + + /** + * Returns the raw JSON value of [fieldValue]. + * + * Unlike [fieldValue], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("fieldValue") + @ExcludeMissing + fun _fieldValue(): JsonField = fieldValue + + /** + * Returns the raw JSON value of [requirementType]. + * + * Unlike [requirementType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("requirementType") + @ExcludeMissing + fun _requirementType(): JsonField = requirementType + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RegulatoryRequirement]. + * + * The following fields are required: + * ```java + * .fieldValue() + * .requirementType() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RegulatoryRequirement]. */ + class Builder internal constructor() { + + private var fieldValue: JsonField? = null + private var requirementType: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(regulatoryRequirement: RegulatoryRequirement) = apply { + fieldValue = regulatoryRequirement.fieldValue + requirementType = regulatoryRequirement.requirementType + additionalProperties = regulatoryRequirement.additionalProperties.toMutableMap() + } + + /** + * Depends on the requirement's `type`: the text itself for `textual`; for `address`, + * the `id` of an address created in this project with `POST /v1/addresses`; for + * `document`, the `id` of a document created with `POST /v1/documents`. An address or + * document from another project, or one rejected in review, is refused. + */ + fun fieldValue(fieldValue: String) = fieldValue(JsonField.of(fieldValue)) + + /** + * Sets [Builder.fieldValue] to an arbitrary JSON value. + * + * You should usually call [Builder.fieldValue] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fieldValue(fieldValue: JsonField) = apply { this.fieldValue = fieldValue } + + /** + * A `requirementTypes[].id` from `GET /v1/phone-numbers/requirements`. Each id may + * appear only once. + */ + fun requirementType(requirementType: String) = + requirementType(JsonField.of(requirementType)) + + /** + * Sets [Builder.requirementType] to an arbitrary JSON value. + * + * You should usually call [Builder.requirementType] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun requirementType(requirementType: JsonField) = apply { + this.requirementType = requirementType + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [RegulatoryRequirement]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .fieldValue() + * .requirementType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RegulatoryRequirement = + RegulatoryRequirement( + checkRequired("fieldValue", fieldValue), + checkRequired("requirementType", requirementType), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws ZavudevInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): RegulatoryRequirement = apply { + if (validated) { + return@apply + } + + fieldValue() + requirementType() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: ZavudevInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (fieldValue.asKnown().isPresent) 1 else 0) + + (if (requirementType.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RegulatoryRequirement && + fieldValue == other.fieldValue && + requirementType == other.requirementType && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(phoneNumber, name, additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(fieldValue, requirementType, additionalProperties) + } override fun hashCode(): Int = hashCode override fun toString() = - "Body{phoneNumber=$phoneNumber, name=$name, additionalProperties=$additionalProperties}" + "RegulatoryRequirement{fieldValue=$fieldValue, requirementType=$requirementType, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParams.kt index c0e0972..8e2ca5e 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParams.kt @@ -3,7 +3,6 @@ package com.zavudev.api.models.phonenumbers import com.zavudev.api.core.Params -import com.zavudev.api.core.checkRequired import com.zavudev.api.core.http.Headers import com.zavudev.api.core.http.QueryParams import java.util.Objects @@ -11,22 +10,42 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Get regulatory requirements for purchasing phone numbers in a specific country. Some countries - * require additional documentation (addresses, identity documents) before phone numbers can be - * activated. + * Get the regulatory information needed to buy a phone number, for one specific number or for a + * country and number type. Prefer `phoneNumber`: the response is then exactly the list the purchase + * of that number validates against. Pass each `requirementTypes[].id` back as `requirementType` in + * `regulatoryRequirements` on `POST /v1/phone-numbers`. + * + * For `phoneNumber`, the requirements of that exact number are returned. When they cannot be + * resolved for the number itself, the list for its country and `type` is returned instead, and the + * purchase uses the same list. An empty `items` array means the number needs no regulatory + * information. If the requirements cannot be retrieved at all, the response is `502 + * requirements_unavailable`, never an empty list. + * + * URL-encode the `+` of `phoneNumber` as `%2B`. An unencoded `+` is also accepted. */ class PhoneNumberRequirementsParams private constructor( - private val countryCode: String, + private val countryCode: String?, + private val phoneNumber: String?, private val type: PhoneNumberType?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - /** Two-letter ISO country code. */ - fun countryCode(): String = countryCode + /** Two-letter ISO country code. Required unless `phoneNumber` is given. */ + fun countryCode(): Optional = Optional.ofNullable(countryCode) - /** Type of phone number (local, mobile, tollFree). */ + /** + * E.164 number from `GET /v1/phone-numbers/available`, with `+` encoded as `%2B`. Returns the + * requirements the purchase of that number checks. Takes precedence over `countryCode`. + */ + fun phoneNumber(): Optional = Optional.ofNullable(phoneNumber) + + /** + * Type of phone number (local, national, mobile, tollFree). Defaults to `local`. With + * `phoneNumber`, used only when the number's own requirements cannot be resolved and the + * country list is returned. + */ fun type(): Optional = Optional.ofNullable(type) /** Additional headers to send with the request. */ @@ -39,14 +58,11 @@ private constructor( companion object { + @JvmStatic fun none(): PhoneNumberRequirementsParams = builder().build() + /** * Returns a mutable builder for constructing an instance of * [PhoneNumberRequirementsParams]. - * - * The following fields are required: - * ```java - * .countryCode() - * ``` */ @JvmStatic fun builder() = Builder() } @@ -55,6 +71,7 @@ private constructor( class Builder internal constructor() { private var countryCode: String? = null + private var phoneNumber: String? = null private var type: PhoneNumberType? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -62,15 +79,32 @@ private constructor( @JvmSynthetic internal fun from(phoneNumberRequirementsParams: PhoneNumberRequirementsParams) = apply { countryCode = phoneNumberRequirementsParams.countryCode + phoneNumber = phoneNumberRequirementsParams.phoneNumber type = phoneNumberRequirementsParams.type additionalHeaders = phoneNumberRequirementsParams.additionalHeaders.toBuilder() additionalQueryParams = phoneNumberRequirementsParams.additionalQueryParams.toBuilder() } - /** Two-letter ISO country code. */ - fun countryCode(countryCode: String) = apply { this.countryCode = countryCode } + /** Two-letter ISO country code. Required unless `phoneNumber` is given. */ + fun countryCode(countryCode: String?) = apply { this.countryCode = countryCode } + + /** Alias for calling [Builder.countryCode] with `countryCode.orElse(null)`. */ + fun countryCode(countryCode: Optional) = countryCode(countryCode.getOrNull()) + + /** + * E.164 number from `GET /v1/phone-numbers/available`, with `+` encoded as `%2B`. Returns + * the requirements the purchase of that number checks. Takes precedence over `countryCode`. + */ + fun phoneNumber(phoneNumber: String?) = apply { this.phoneNumber = phoneNumber } + + /** Alias for calling [Builder.phoneNumber] with `phoneNumber.orElse(null)`. */ + fun phoneNumber(phoneNumber: Optional) = phoneNumber(phoneNumber.getOrNull()) - /** Type of phone number (local, mobile, tollFree). */ + /** + * Type of phone number (local, national, mobile, tollFree). Defaults to `local`. With + * `phoneNumber`, used only when the number's own requirements cannot be resolved and the + * country list is returned. + */ fun type(type: PhoneNumberType?) = apply { this.type = type } /** Alias for calling [Builder.type] with `type.orElse(null)`. */ @@ -178,17 +212,11 @@ private constructor( * Returns an immutable instance of [PhoneNumberRequirementsParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .countryCode() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): PhoneNumberRequirementsParams = PhoneNumberRequirementsParams( - checkRequired("countryCode", countryCode), + countryCode, + phoneNumber, type, additionalHeaders.build(), additionalQueryParams.build(), @@ -200,7 +228,8 @@ private constructor( override fun _queryParams(): QueryParams = QueryParams.builder() .apply { - put("countryCode", countryCode) + countryCode?.let { put("countryCode", it) } + phoneNumber?.let { put("phoneNumber", it) } type?.let { put("type", it.toString()) } putAll(additionalQueryParams) } @@ -213,14 +242,15 @@ private constructor( return other is PhoneNumberRequirementsParams && countryCode == other.countryCode && + phoneNumber == other.phoneNumber && type == other.type && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } override fun hashCode(): Int = - Objects.hash(countryCode, type, additionalHeaders, additionalQueryParams) + Objects.hash(countryCode, phoneNumber, type, additionalHeaders, additionalQueryParams) override fun toString() = - "PhoneNumberRequirementsParams{countryCode=$countryCode, type=$type, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "PhoneNumberRequirementsParams{countryCode=$countryCode, phoneNumber=$phoneNumber, type=$type, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberStatus.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberStatus.kt index 5bffac7..bdd72ce 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberStatus.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberStatus.kt @@ -7,6 +7,11 @@ import com.zavudev.api.core.Enum import com.zavudev.api.core.JsonField import com.zavudev.api.errors.ZavudevInvalidDataException +/** + * Billing state of an owned number, separate from `regulatoryStatus`. `pending` is legacy and is + * not written to numbers today. The SDKs carry `active`, `suspended` and `pending` only; + * `releasing` and `released` are returned by the REST API until their next release. + */ class PhoneNumberStatus @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -27,6 +32,10 @@ class PhoneNumberStatus @JsonCreator private constructor(private val value: Json @JvmField val PENDING = of("pending") + @JvmField val RELEASING = of("releasing") + + @JvmField val RELEASED = of("released") + @JvmStatic fun of(value: String) = PhoneNumberStatus(JsonField.of(value)) } @@ -35,6 +44,8 @@ class PhoneNumberStatus @JsonCreator private constructor(private val value: Json ACTIVE, SUSPENDED, PENDING, + RELEASING, + RELEASED, } /** @@ -50,6 +61,8 @@ class PhoneNumberStatus @JsonCreator private constructor(private val value: Json ACTIVE, SUSPENDED, PENDING, + RELEASING, + RELEASED, /** * An enum member indicating that [PhoneNumberStatus] was instantiated with an unknown * value. @@ -69,6 +82,8 @@ class PhoneNumberStatus @JsonCreator private constructor(private val value: Json ACTIVE -> Value.ACTIVE SUSPENDED -> Value.SUSPENDED PENDING -> Value.PENDING + RELEASING -> Value.RELEASING + RELEASED -> Value.RELEASED else -> Value._UNKNOWN } @@ -85,6 +100,8 @@ class PhoneNumberStatus @JsonCreator private constructor(private val value: Json ACTIVE -> Known.ACTIVE SUSPENDED -> Known.SUSPENDED PENDING -> Known.PENDING + RELEASING -> Known.RELEASING + RELEASED -> Known.RELEASED else -> throw ZavudevInvalidDataException("Unknown PhoneNumberStatus: $value") } diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateParams.kt index 2c1e3a4..372021e 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateParams.kt @@ -39,7 +39,9 @@ private constructor( fun name(): Optional = body.name() /** - * Sender ID to assign the phone number to. Set to null to unassign. + * Sender ID to assign the phone number to. Set to null to unassign. A number under regulatory + * review is recorded now and connected to the sender when approved; a rejected number is + * refused. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -124,7 +126,11 @@ private constructor( */ fun name(name: JsonField) = apply { body.name(name) } - /** Sender ID to assign the phone number to. Set to null to unassign. */ + /** + * Sender ID to assign the phone number to. Set to null to unassign. A number under + * regulatory review is recorded now and connected to the sender when approved; a rejected + * number is refused. + */ fun senderId(senderId: String?) = apply { body.senderId(senderId) } /** Alias for calling [Builder.senderId] with `senderId.orElse(null)`. */ @@ -304,7 +310,9 @@ private constructor( fun name(): Optional = name.getOptional("name") /** - * Sender ID to assign the phone number to. Set to null to unassign. + * Sender ID to assign the phone number to. Set to null to unassign. A number under + * regulatory review is recorded now and connected to the sender when approved; a rejected + * number is refused. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -372,7 +380,11 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** Sender ID to assign the phone number to. Set to null to unassign. */ + /** + * Sender ID to assign the phone number to. Set to null to unassign. A number under + * regulatory review is recorded now and connected to the sender when approved; a + * rejected number is refused. + */ fun senderId(senderId: String?) = senderId(JsonField.ofNullable(senderId)) /** Alias for calling [Builder.senderId] with `senderId.orElse(null)`. */ diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/Requirement.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/Requirement.kt index f06a180..e3c9690 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/Requirement.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/Requirement.kt @@ -18,7 +18,11 @@ import java.util.Collections import java.util.Objects import kotlin.jvm.optionals.getOrNull -/** A group of requirements for a specific country/phone type combination. */ +/** + * The requirements for ordering a number: for a country and number type, or for one specific number + * when requested with `phoneNumber` (then `id` is that phone number and `countryCode` is taken from + * it). + */ class Requirement @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/RequirementType.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/RequirementType.kt index 09ea4f6..ab9501c 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/RequirementType.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/phonenumbers/RequirementType.kt @@ -47,6 +47,8 @@ private constructor( ) : this(id, description, name, type, acceptanceCriteria, example, mutableMapOf()) /** + * Send this as `requirementType` in `regulatoryRequirements` when purchasing. + * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ @@ -182,6 +184,7 @@ private constructor( additionalProperties = requirementType.additionalProperties.toMutableMap() } + /** Send this as `requirementType` in `regulatoryRequirements` when purchasing. */ fun id(id: String) = id(JsonField.of(id)) /** diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/Sender.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/Sender.kt index 771909f..b622a0e 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/Sender.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/Sender.kt @@ -105,9 +105,11 @@ private constructor( fun phoneNumber(): String = phoneNumber.getRequired("phoneNumber") /** - * Channels this sender can actually send on right now, computed from its configuration. Empty - * means the sender cannot send or receive anything yet: a phoneNumber alone does not enable SMS - * or voice. Check this rather than inferring capability from phoneNumber or emailAddress. + * Channels this sender can actually send on right now: configured AND activated. Empty means + * the sender cannot send or receive anything yet: a phoneNumber alone does not enable SMS or + * voice, and a connected account that is not activated is left out, because every send on it is + * refused. Check this rather than inferring capability from phoneNumber or emailAddress, and + * turn a connected channel on with `POST /v1/senders/{senderId}/channels/{channel}/activate`. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -368,10 +370,12 @@ private constructor( fun phoneNumber(phoneNumber: JsonField) = apply { this.phoneNumber = phoneNumber } /** - * Channels this sender can actually send on right now, computed from its configuration. - * Empty means the sender cannot send or receive anything yet: a phoneNumber alone does not - * enable SMS or voice. Check this rather than inferring capability from phoneNumber or - * emailAddress. + * Channels this sender can actually send on right now: configured AND activated. Empty + * means the sender cannot send or receive anything yet: a phoneNumber alone does not enable + * SMS or voice, and a connected account that is not activated is left out, because every + * send on it is refused. Check this rather than inferring capability from phoneNumber or + * emailAddress, and turn a connected channel on with `POST + * /v1/senders/{senderId}/channels/{channel}/activate`. */ fun channels(channels: List) = channels(JsonField.of(channels)) diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderCreateParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderCreateParams.kt index 26b0498..4b9f4a1 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderCreateParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderCreateParams.kt @@ -65,8 +65,9 @@ private constructor( fun emailFromName(): Optional = body.emailFromName() /** - * Enable inbound email receiving on this sender. Requires a verified MX record on the domain; - * ignored otherwise. + * Enable inbound email receiving on this sender. Requires a verified inbound MX record on the + * domain; the request is ignored otherwise. Read `emailReceivingEnabled` back off the response + * to see whether it was applied — it comes back `false` when the MX has not verified. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -95,9 +96,10 @@ private constructor( /** * Phone number in E.164 format, and it must be a number your project already owns (see `GET * /v1/phone-numbers`). The number is routed to the sender as part of this call, which is what - * turns the SMS channel on. Passing a number the project does not own, or one already attached - * to another sender, returns 400 rather than creating a sender that cannot send. Omit for an - * email-only sender. + * turns the SMS channel on. Passing a number the project does not own, one already attached to + * another sender, or one rejected in regulatory review returns 400 rather than creating a + * sender that cannot send. A number still under review is attached and starts carrying messages + * when it is approved. Omit for an email-only sender. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -342,8 +344,10 @@ private constructor( } /** - * Enable inbound email receiving on this sender. Requires a verified MX record on the - * domain; ignored otherwise. + * Enable inbound email receiving on this sender. Requires a verified inbound MX record on + * the domain; the request is ignored otherwise. Read `emailReceivingEnabled` back off the + * response to see whether it was applied — it comes back `false` when the MX has not + * verified. */ fun emailReceivingEnabled(emailReceivingEnabled: Boolean) = apply { body.emailReceivingEnabled(emailReceivingEnabled) @@ -398,9 +402,10 @@ private constructor( /** * Phone number in E.164 format, and it must be a number your project already owns (see `GET * /v1/phone-numbers`). The number is routed to the sender as part of this call, which is - * what turns the SMS channel on. Passing a number the project does not own, or one already - * attached to another sender, returns 400 rather than creating a sender that cannot send. - * Omit for an email-only sender. + * what turns the SMS channel on. Passing a number the project does not own, one already + * attached to another sender, or one rejected in regulatory review returns 400 rather than + * creating a sender that cannot send. A number still under review is attached and starts + * carrying messages when it is approved. Omit for an email-only sender. */ fun phoneNumber(phoneNumber: String) = apply { body.phoneNumber(phoneNumber) } @@ -744,8 +749,10 @@ private constructor( fun emailFromName(): Optional = emailFromName.getOptional("emailFromName") /** - * Enable inbound email receiving on this sender. Requires a verified MX record on the - * domain; ignored otherwise. + * Enable inbound email receiving on this sender. Requires a verified inbound MX record on + * the domain; the request is ignored otherwise. Read `emailReceivingEnabled` back off the + * response to see whether it was applied — it comes back `false` when the MX has not + * verified. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -775,9 +782,10 @@ private constructor( /** * Phone number in E.164 format, and it must be a number your project already owns (see `GET * /v1/phone-numbers`). The number is routed to the sender as part of this call, which is - * what turns the SMS channel on. Passing a number the project does not own, or one already - * attached to another sender, returns 400 rather than creating a sender that cannot send. - * Omit for an email-only sender. + * what turns the SMS channel on. Passing a number the project does not own, one already + * attached to another sender, or one rejected in regulatory review returns 400 rather than + * creating a sender that cannot send. A number still under review is attached and starts + * carrying messages when it is approved. Omit for an email-only sender. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -1061,8 +1069,10 @@ private constructor( } /** - * Enable inbound email receiving on this sender. Requires a verified MX record on the - * domain; ignored otherwise. + * Enable inbound email receiving on this sender. Requires a verified inbound MX record + * on the domain; the request is ignored otherwise. Read `emailReceivingEnabled` back + * off the response to see whether it was applied — it comes back `false` when the MX + * has not verified. */ fun emailReceivingEnabled(emailReceivingEnabled: Boolean) = emailReceivingEnabled(JsonField.of(emailReceivingEnabled)) @@ -1118,9 +1128,11 @@ private constructor( /** * Phone number in E.164 format, and it must be a number your project already owns (see * `GET /v1/phone-numbers`). The number is routed to the sender as part of this call, - * which is what turns the SMS channel on. Passing a number the project does not own, or - * one already attached to another sender, returns 400 rather than creating a sender - * that cannot send. Omit for an email-only sender. + * which is what turns the SMS channel on. Passing a number the project does not own, + * one already attached to another sender, or one rejected in regulatory review returns + * 400 rather than creating a sender that cannot send. A number still under review is + * attached and starts carrying messages when it is approved. Omit for an email-only + * sender. */ fun phoneNumber(phoneNumber: String) = phoneNumber(JsonField.of(phoneNumber)) diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderUpdateParams.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderUpdateParams.kt index 1461e3b..045d71a 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderUpdateParams.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/SenderUpdateParams.kt @@ -70,7 +70,9 @@ private constructor( fun emailFromName(): Optional = body.emailFromName() /** - * Enable or disable inbound email receiving for this sender. + * Enable or disable inbound email receiving for this sender. Enabling requires a verified + * inbound MX record on the domain; the request is ignored otherwise, and + * `emailReceivingEnabled` comes back `false` on the response. Disabling always applies. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -367,7 +369,11 @@ private constructor( body.emailFromName(emailFromName) } - /** Enable or disable inbound email receiving for this sender. */ + /** + * Enable or disable inbound email receiving for this sender. Enabling requires a verified + * inbound MX record on the domain; the request is ignored otherwise, and + * `emailReceivingEnabled` comes back `false` on the response. Disabling always applies. + */ fun emailReceivingEnabled(emailReceivingEnabled: Boolean) = apply { body.emailReceivingEnabled(emailReceivingEnabled) } @@ -781,7 +787,9 @@ private constructor( fun emailFromName(): Optional = emailFromName.getOptional("emailFromName") /** - * Enable or disable inbound email receiving for this sender. + * Enable or disable inbound email receiving for this sender. Enabling requires a verified + * inbound MX record on the domain; the request is ignored otherwise, and + * `emailReceivingEnabled` comes back `false` on the response. Disabling always applies. * * @throws ZavudevInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -1112,7 +1120,11 @@ private constructor( this.emailFromName = emailFromName } - /** Enable or disable inbound email receiving for this sender. */ + /** + * Enable or disable inbound email receiving for this sender. Enabling requires a + * verified inbound MX record on the domain; the request is ignored otherwise, and + * `emailReceivingEnabled` comes back `false` on the response. Disabling always applies. + */ fun emailReceivingEnabled(emailReceivingEnabled: Boolean) = emailReceivingEnabled(JsonField.of(emailReceivingEnabled)) diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/WebhookEvent.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/WebhookEvent.kt index 336361f..a32bc3e 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/WebhookEvent.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/models/senders/WebhookEvent.kt @@ -48,12 +48,17 @@ import com.zavudev.api.errors.ZavudevInvalidDataException * - `template.status_changed`: WhatsApp template approval status changed * * **Partner events:** - * - `invitation.status_changed`: A partner invitation status changed (pending, in_progress, - * completed, cancelled, failed). `data` carries `invitationId`, `clientName`, `clientEmail`, + * - `invitation.status_changed`: A partner invitation's stored status changed: to `in_progress`, + * `completed`, `failed`, `cancelled`, or back to `pending` when it is resent from the dashboard. + * A change to the same status sends nothing, and expiry is not a stored change, so no event is + * sent when an invitation expires. Delivered to the project webhook (`POST + * /v1/invitations/webhook`) of the project that created the invitation; a parent project does not + * receive its sub-accounts' events. `data` carries `invitationId`, `clientName`, `clientEmail`, * `connectionType` (`whatsapp_waba` or `messenger`), `previousStatus`, and `currentStatus`. On - * `completed` it also carries `senderId` and `connectedAccount` (`channel`, `id`, `name`) — the - * WhatsApp number or Facebook Page that was linked. On `failed` it carries `failureReason`; the - * invitation link stays usable, so a client can retry it. + * `completed` it also carries `senderId`, `connectedAccount` (`channel`, `id`, `name`) — the + * WhatsApp number or Facebook Page that was linked — and, for WhatsApp, `wabaAccountId`. On + * `failed` it carries `failureReason`; the invitation link stays usable, so a client can retry + * it. * * **Voice Agent events:** For every voice event, `data` carries `callId`, `direction`, `from`, * `to`, `status`, `durationSeconds`, `endReason`, and `transcriptAvailable`. The terminal events diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/AddressServiceAsync.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/AddressServiceAsync.kt index d250aa8..8835d60 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/AddressServiceAsync.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/AddressServiceAsync.kt @@ -31,8 +31,8 @@ interface AddressServiceAsync { fun withOptions(modifier: Consumer): AddressServiceAsync /** - * Create a regulatory address for phone number purchases. Some countries require a verified - * address before phone numbers can be activated. + * Create a regulatory address, to use as the value of an `address` requirement when buying a + * phone number. It is registered for review when it is created, with status `pending`. */ fun create(params: AddressCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -97,7 +97,11 @@ interface AddressServiceAsync { fun list(requestOptions: RequestOptions): CompletableFuture = list(AddressListParams.none(), requestOptions) - /** Delete a regulatory address. Cannot delete addresses that are in use. */ + /** + * Delete a regulatory address from this project. Any address can be deleted, whatever its + * status. Phone numbers already purchased with it are not affected, and neither is information + * already submitted for later purchases in its country. + */ fun delete(addressId: String): CompletableFuture = delete(addressId, AddressDeleteParams.none()) diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsync.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsync.kt index 04e5d42..32b7b84 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsync.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsync.kt @@ -129,10 +129,37 @@ interface PhoneNumberServiceAsync { /** * Purchase an available phone number. Requires a paid plan: the Free plan cannot purchase phone - * numbers and receives `402` with code `paid_plan_required`. Paid plans include one US number - * at no charge. The included number is one per account and is granted once: claiming it spends - * the benefit for good, so releasing that number does not make another one free, and numbers - * the account already bought do not consume it. + * numbers and receives `402` with code `paid_plan_required`. + * + * **The included number.** A paid plan includes one number at no charge, once per account: it + * must be a US or Canadian number (a +1 number) costing $20 a month or less. `isFreeEligible` + * in `GET /v1/phone-numbers/available` marks the numbers that qualify. Claiming it spends the + * benefit for good, across every team the account owner owns, so releasing that number does not + * make another one free. + * + * **Numbers with regulatory requirements.** Which numbers need regulatory information is + * decided per number, not by a fixed country list. The purchase looks the requirements up for + * the exact number before charging anything: + * 1. `GET /v1/phone-numbers/requirements?phoneNumber=...`. If `items` is empty, buy normally. + * 2. Create what it asks for: addresses with `POST /v1/addresses`, documents with `POST + * /v1/documents`. + * 3. Purchase with `type` and `regulatoryRequirements`. The number is bought and billed at once + * with `regulatoryStatus: pending_review`. + * 4. Poll `GET /v1/phone-numbers/{phoneNumberId}` until `regulatoryStatus` is `approved`. + * Assign it to a sender before or after approval; it starts carrying messages once approved. + * + * **Reuse.** Information you submitted is kept for your project, per country and `type`, and a + * later purchase there may omit `regulatoryRequirements`. Reuse only happens when what is kept + * still covers every requirement of the new number and every address and document in it belongs + * to the project. Otherwise, or when nothing is kept, the purchase returns `400 + * regulatory_compliance_required` with the missing requirements in `details`. + * + * Invalid values (a missing, unknown or repeated requirement id, an address or document from + * another project, or one rejected in review) return `400 invalid_request`. If an address or + * document cannot be registered for review, the purchase returns `400 invalid_request` naming + * the requirement. If the requirements cannot be looked up, the purchase returns `502 + * requirements_unavailable`, except for US and Canadian numbers, which are sold as numbers + * without requirements. None of these errors charge anything. */ fun purchase( params: PhoneNumberPurchaseParams @@ -177,20 +204,39 @@ interface PhoneNumberServiceAsync { release(phoneNumberId, PhoneNumberReleaseParams.none(), requestOptions) /** - * Get regulatory requirements for purchasing phone numbers in a specific country. Some - * countries require additional documentation (addresses, identity documents) before phone - * numbers can be activated. + * Get the regulatory information needed to buy a phone number, for one specific number or for a + * country and number type. Prefer `phoneNumber`: the response is then exactly the list the + * purchase of that number validates against. Pass each `requirementTypes[].id` back as + * `requirementType` in `regulatoryRequirements` on `POST /v1/phone-numbers`. + * + * For `phoneNumber`, the requirements of that exact number are returned. When they cannot be + * resolved for the number itself, the list for its country and `type` is returned instead, and + * the purchase uses the same list. An empty `items` array means the number needs no regulatory + * information. If the requirements cannot be retrieved at all, the response is `502 + * requirements_unavailable`, never an empty list. + * + * URL-encode the `+` of `phoneNumber` as `%2B`. An unencoded `+` is also accepted. */ + fun requirements(): CompletableFuture = + requirements(PhoneNumberRequirementsParams.none()) + + /** @see requirements */ fun requirements( - params: PhoneNumberRequirementsParams + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see requirements */ + fun requirements( + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none() ): CompletableFuture = requirements(params, RequestOptions.none()) /** @see requirements */ fun requirements( - params: PhoneNumberRequirementsParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + requestOptions: RequestOptions + ): CompletableFuture = + requirements(PhoneNumberRequirementsParams.none(), requestOptions) /** Search for available phone numbers to purchase by country and type. */ fun searchAvailable( @@ -387,16 +433,26 @@ interface PhoneNumberServiceAsync { * Returns a raw HTTP response for `get /v1/phone-numbers/requirements`, but is otherwise * the same as [PhoneNumberServiceAsync.requirements]. */ + fun requirements(): CompletableFuture> = + requirements(PhoneNumberRequirementsParams.none()) + + /** @see requirements */ fun requirements( - params: PhoneNumberRequirementsParams + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see requirements */ + fun requirements( + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none() ): CompletableFuture> = requirements(params, RequestOptions.none()) /** @see requirements */ fun requirements( - params: PhoneNumberRequirementsParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + requestOptions: RequestOptions + ): CompletableFuture> = + requirements(PhoneNumberRequirementsParams.none(), requestOptions) /** * Returns a raw HTTP response for `get /v1/phone-numbers/available`, but is otherwise the diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/AddressService.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/AddressService.kt index bb2e071..2b0779b 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/AddressService.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/AddressService.kt @@ -31,8 +31,8 @@ interface AddressService { fun withOptions(modifier: Consumer): AddressService /** - * Create a regulatory address for phone number purchases. Some countries require a verified - * address before phone numbers can be activated. + * Create a regulatory address, to use as the value of an `address` requirement when buying a + * phone number. It is registered for review when it is created, with status `pending`. */ fun create(params: AddressCreateParams): AddressCreateResponse = create(params, RequestOptions.none()) @@ -92,7 +92,11 @@ interface AddressService { fun list(requestOptions: RequestOptions): AddressListPage = list(AddressListParams.none(), requestOptions) - /** Delete a regulatory address. Cannot delete addresses that are in use. */ + /** + * Delete a regulatory address from this project. Any address can be deleted, whatever its + * status. Phone numbers already purchased with it are not affected, and neither is information + * already submitted for later purchases in its country. + */ fun delete(addressId: String) = delete(addressId, AddressDeleteParams.none()) /** @see delete */ diff --git a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/PhoneNumberService.kt b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/PhoneNumberService.kt index c4b874b..e8bc11a 100644 --- a/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/PhoneNumberService.kt +++ b/zavudev-java-core/src/main/kotlin/com/zavudev/api/services/blocking/PhoneNumberService.kt @@ -122,10 +122,37 @@ interface PhoneNumberService { /** * Purchase an available phone number. Requires a paid plan: the Free plan cannot purchase phone - * numbers and receives `402` with code `paid_plan_required`. Paid plans include one US number - * at no charge. The included number is one per account and is granted once: claiming it spends - * the benefit for good, so releasing that number does not make another one free, and numbers - * the account already bought do not consume it. + * numbers and receives `402` with code `paid_plan_required`. + * + * **The included number.** A paid plan includes one number at no charge, once per account: it + * must be a US or Canadian number (a +1 number) costing $20 a month or less. `isFreeEligible` + * in `GET /v1/phone-numbers/available` marks the numbers that qualify. Claiming it spends the + * benefit for good, across every team the account owner owns, so releasing that number does not + * make another one free. + * + * **Numbers with regulatory requirements.** Which numbers need regulatory information is + * decided per number, not by a fixed country list. The purchase looks the requirements up for + * the exact number before charging anything: + * 1. `GET /v1/phone-numbers/requirements?phoneNumber=...`. If `items` is empty, buy normally. + * 2. Create what it asks for: addresses with `POST /v1/addresses`, documents with `POST + * /v1/documents`. + * 3. Purchase with `type` and `regulatoryRequirements`. The number is bought and billed at once + * with `regulatoryStatus: pending_review`. + * 4. Poll `GET /v1/phone-numbers/{phoneNumberId}` until `regulatoryStatus` is `approved`. + * Assign it to a sender before or after approval; it starts carrying messages once approved. + * + * **Reuse.** Information you submitted is kept for your project, per country and `type`, and a + * later purchase there may omit `regulatoryRequirements`. Reuse only happens when what is kept + * still covers every requirement of the new number and every address and document in it belongs + * to the project. Otherwise, or when nothing is kept, the purchase returns `400 + * regulatory_compliance_required` with the missing requirements in `details`. + * + * Invalid values (a missing, unknown or repeated requirement id, an address or document from + * another project, or one rejected in review) return `400 invalid_request`. If an address or + * document cannot be registered for review, the purchase returns `400 invalid_request` naming + * the requirement. If the requirements cannot be looked up, the purchase returns `502 + * requirements_unavailable`, except for US and Canadian numbers, which are sold as numbers + * without requirements. None of these errors charge anything. */ fun purchase(params: PhoneNumberPurchaseParams): PhoneNumberPurchaseResponse = purchase(params, RequestOptions.none()) @@ -166,19 +193,37 @@ interface PhoneNumberService { release(phoneNumberId, PhoneNumberReleaseParams.none(), requestOptions) /** - * Get regulatory requirements for purchasing phone numbers in a specific country. Some - * countries require additional documentation (addresses, identity documents) before phone - * numbers can be activated. + * Get the regulatory information needed to buy a phone number, for one specific number or for a + * country and number type. Prefer `phoneNumber`: the response is then exactly the list the + * purchase of that number validates against. Pass each `requirementTypes[].id` back as + * `requirementType` in `regulatoryRequirements` on `POST /v1/phone-numbers`. + * + * For `phoneNumber`, the requirements of that exact number are returned. When they cannot be + * resolved for the number itself, the list for its country and `type` is returned instead, and + * the purchase uses the same list. An empty `items` array means the number needs no regulatory + * information. If the requirements cannot be retrieved at all, the response is `502 + * requirements_unavailable`, never an empty list. + * + * URL-encode the `+` of `phoneNumber` as `%2B`. An unencoded `+` is also accepted. */ - fun requirements(params: PhoneNumberRequirementsParams): PhoneNumberRequirementsResponse = - requirements(params, RequestOptions.none()) + fun requirements(): PhoneNumberRequirementsResponse = + requirements(PhoneNumberRequirementsParams.none()) /** @see requirements */ fun requirements( - params: PhoneNumberRequirementsParams, + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): PhoneNumberRequirementsResponse + /** @see requirements */ + fun requirements( + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none() + ): PhoneNumberRequirementsResponse = requirements(params, RequestOptions.none()) + + /** @see requirements */ + fun requirements(requestOptions: RequestOptions): PhoneNumberRequirementsResponse = + requirements(PhoneNumberRequirementsParams.none(), requestOptions) + /** Search for available phone numbers to purchase by country and type. */ fun searchAvailable( params: PhoneNumberSearchAvailableParams @@ -382,17 +427,29 @@ interface PhoneNumberService { * the same as [PhoneNumberService.requirements]. */ @MustBeClosed + fun requirements(): HttpResponseFor = + requirements(PhoneNumberRequirementsParams.none()) + + /** @see requirements */ + @MustBeClosed fun requirements( - params: PhoneNumberRequirementsParams + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see requirements */ + @MustBeClosed + fun requirements( + params: PhoneNumberRequirementsParams = PhoneNumberRequirementsParams.none() ): HttpResponseFor = requirements(params, RequestOptions.none()) /** @see requirements */ @MustBeClosed fun requirements( - params: PhoneNumberRequirementsParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + requestOptions: RequestOptions + ): HttpResponseFor = + requirements(PhoneNumberRequirementsParams.none(), requestOptions) /** * Returns a raw HTTP response for `get /v1/phone-numbers/available`, but is otherwise the diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/addresses/AddressCreateParamsTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/addresses/AddressCreateParamsTest.kt index 855df03..1301417 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/addresses/AddressCreateParamsTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/addresses/AddressCreateParamsTest.kt @@ -11,14 +11,14 @@ internal class AddressCreateParamsTest { fun create() { AddressCreateParams.builder() .countryCode("DE") + .firstName("John") + .lastName("Doe") .locality("Berlin") .postalCode("10115") .streetAddress("123 Main St") .administrativeArea("administrativeArea") .businessName("businessName") .extendedAddress("extendedAddress") - .firstName("John") - .lastName("Doe") .build() } @@ -27,27 +27,27 @@ internal class AddressCreateParamsTest { val params = AddressCreateParams.builder() .countryCode("DE") + .firstName("John") + .lastName("Doe") .locality("Berlin") .postalCode("10115") .streetAddress("123 Main St") .administrativeArea("administrativeArea") .businessName("businessName") .extendedAddress("extendedAddress") - .firstName("John") - .lastName("Doe") .build() val body = params._body() assertThat(body.countryCode()).isEqualTo("DE") + assertThat(body.firstName()).isEqualTo("John") + assertThat(body.lastName()).isEqualTo("Doe") assertThat(body.locality()).isEqualTo("Berlin") assertThat(body.postalCode()).isEqualTo("10115") assertThat(body.streetAddress()).isEqualTo("123 Main St") assertThat(body.administrativeArea()).contains("administrativeArea") assertThat(body.businessName()).contains("businessName") assertThat(body.extendedAddress()).contains("extendedAddress") - assertThat(body.firstName()).contains("John") - assertThat(body.lastName()).contains("Doe") } @Test @@ -55,6 +55,8 @@ internal class AddressCreateParamsTest { val params = AddressCreateParams.builder() .countryCode("DE") + .firstName("John") + .lastName("Doe") .locality("Berlin") .postalCode("10115") .streetAddress("123 Main St") @@ -63,6 +65,8 @@ internal class AddressCreateParamsTest { val body = params._body() assertThat(body.countryCode()).isEqualTo("DE") + assertThat(body.firstName()).isEqualTo("John") + assertThat(body.lastName()).isEqualTo("Doe") assertThat(body.locality()).isEqualTo("Berlin") assertThat(body.postalCode()).isEqualTo("10115") assertThat(body.streetAddress()).isEqualTo("123 Main St") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandCreateResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandCreateResponseTest.kt index b6b298e..0d7ad33 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandCreateResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandCreateResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandCreateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -69,6 +70,7 @@ internal class BrandCreateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -106,6 +108,7 @@ internal class BrandCreateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandListPageResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandListPageResponseTest.kt index a8bb944..842150e 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandListPageResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandListPageResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandListPageResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -70,6 +71,7 @@ internal class BrandListPageResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -108,6 +110,7 @@ internal class BrandListPageResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandRetrieveResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandRetrieveResponseTest.kt index 5bca42c..0320317 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandRetrieveResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandRetrieveResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandRetrieveResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -69,6 +70,7 @@ internal class BrandRetrieveResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -106,6 +108,7 @@ internal class BrandRetrieveResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSubmitResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSubmitResponseTest.kt index d620783..11d0e6b 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSubmitResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSubmitResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandSubmitResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -69,6 +70,7 @@ internal class BrandSubmitResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -106,6 +108,7 @@ internal class BrandSubmitResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSyncStatusResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSyncStatusResponseTest.kt index 96235a9..a23a784 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSyncStatusResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandSyncStatusResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandSyncStatusResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -69,6 +70,7 @@ internal class BrandSyncStatusResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -106,6 +108,7 @@ internal class BrandSyncStatusResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandUpdateResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandUpdateResponseTest.kt index fddce06..4a9f2e8 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandUpdateResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/BrandUpdateResponseTest.kt @@ -36,6 +36,7 @@ internal class BrandUpdateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -69,6 +70,7 @@ internal class BrandUpdateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -106,6 +108,7 @@ internal class BrandUpdateResponseTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrandTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrandTest.kt index e5fd9fa..f2e608e 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrandTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/number10dlc/brands/TenDlcBrandTest.kt @@ -34,6 +34,7 @@ internal class TenDlcBrandTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") @@ -64,6 +65,7 @@ internal class TenDlcBrandTest { assertThat(tenDlcBrand.ein()).contains("12-3456789") assertThat(tenDlcBrand.failureReason()).contains("failureReason") assertThat(tenDlcBrand.firstName()).contains("firstName") + assertThat(tenDlcBrand.identityStatus()).contains("VERIFIED") assertThat(tenDlcBrand.lastName()).contains("lastName") assertThat(tenDlcBrand.stockExchange()).contains("stockExchange") assertThat(tenDlcBrand.stockSymbol()).contains("stockSymbol") @@ -99,6 +101,7 @@ internal class TenDlcBrandTest { .ein("12-3456789") .failureReason("failureReason") .firstName("firstName") + .identityStatus("VERIFIED") .lastName("lastName") .stockExchange("stockExchange") .stockSymbol("stockSymbol") diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumberTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumberTest.kt index db23b33..d75eb71 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumberTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/OwnedPhoneNumberTest.kt @@ -27,6 +27,7 @@ internal class OwnedPhoneNumberTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -48,6 +49,8 @@ internal class OwnedPhoneNumberTest { .upfrontCost(0.0) .build() ) + assertThat(ownedPhoneNumber.regulatoryStatus()) + .isEqualTo(OwnedPhoneNumber.RegulatoryStatus.APPROVED) assertThat(ownedPhoneNumber.status()).isEqualTo(PhoneNumberStatus.ACTIVE) assertThat(ownedPhoneNumber.name()).contains("name") assertThat(ownedPhoneNumber.nextRenewalDate()) @@ -75,6 +78,7 @@ internal class OwnedPhoneNumberTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberListPageResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberListPageResponseTest.kt index 486a088..6e623eb 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberListPageResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberListPageResponseTest.kt @@ -29,6 +29,7 @@ internal class PhoneNumberListPageResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -55,6 +56,7 @@ internal class PhoneNumberListPageResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -85,6 +87,7 @@ internal class PhoneNumberListPageResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParamsTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParamsTest.kt index b08b7aa..c0853b2 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParamsTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseParamsTest.kt @@ -2,6 +2,7 @@ package com.zavudev.api.models.phonenumbers +import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -9,7 +10,17 @@ internal class PhoneNumberPurchaseParamsTest { @Test fun create() { - PhoneNumberPurchaseParams.builder().phoneNumber("+15551234567").name("Primary Line").build() + PhoneNumberPurchaseParams.builder() + .phoneNumber("+15551234567") + .name("Primary Line") + .addRegulatoryRequirement( + PhoneNumberPurchaseParams.RegulatoryRequirement.builder() + .fieldValue("jd7x2k3m4n5p6q7r8s9t0abc") + .requirementType("8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10") + .build() + ) + .type(PhoneNumberType.LOCAL) + .build() } @Test @@ -18,12 +29,27 @@ internal class PhoneNumberPurchaseParamsTest { PhoneNumberPurchaseParams.builder() .phoneNumber("+15551234567") .name("Primary Line") + .addRegulatoryRequirement( + PhoneNumberPurchaseParams.RegulatoryRequirement.builder() + .fieldValue("jd7x2k3m4n5p6q7r8s9t0abc") + .requirementType("8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10") + .build() + ) + .type(PhoneNumberType.LOCAL) .build() val body = params._body() assertThat(body.phoneNumber()).isEqualTo("+15551234567") assertThat(body.name()).contains("Primary Line") + assertThat(body.regulatoryRequirements().getOrNull()) + .containsExactly( + PhoneNumberPurchaseParams.RegulatoryRequirement.builder() + .fieldValue("jd7x2k3m4n5p6q7r8s9t0abc") + .requirementType("8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10") + .build() + ) + assertThat(body.type()).contains(PhoneNumberType.LOCAL) } @Test diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseResponseTest.kt index be6b848..36c5f67 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberPurchaseResponseTest.kt @@ -29,6 +29,7 @@ internal class PhoneNumberPurchaseResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -54,6 +55,7 @@ internal class PhoneNumberPurchaseResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -83,6 +85,7 @@ internal class PhoneNumberPurchaseResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParamsTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParamsTest.kt index 4215180..6654225 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParamsTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRequirementsParamsTest.kt @@ -12,6 +12,7 @@ internal class PhoneNumberRequirementsParamsTest { fun create() { PhoneNumberRequirementsParams.builder() .countryCode("xx") + .phoneNumber("phoneNumber") .type(PhoneNumberType.LOCAL) .build() } @@ -21,21 +22,28 @@ internal class PhoneNumberRequirementsParamsTest { val params = PhoneNumberRequirementsParams.builder() .countryCode("xx") + .phoneNumber("phoneNumber") .type(PhoneNumberType.LOCAL) .build() val queryParams = params._queryParams() assertThat(queryParams) - .isEqualTo(QueryParams.builder().put("countryCode", "xx").put("type", "local").build()) + .isEqualTo( + QueryParams.builder() + .put("countryCode", "xx") + .put("phoneNumber", "phoneNumber") + .put("type", "local") + .build() + ) } @Test fun queryParamsWithoutOptionalFields() { - val params = PhoneNumberRequirementsParams.builder().countryCode("xx").build() + val params = PhoneNumberRequirementsParams.builder().build() val queryParams = params._queryParams() - assertThat(queryParams).isEqualTo(QueryParams.builder().put("countryCode", "xx").build()) + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRetrieveResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRetrieveResponseTest.kt index 893b5da..8025fe7 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRetrieveResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberRetrieveResponseTest.kt @@ -29,6 +29,7 @@ internal class PhoneNumberRetrieveResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -54,6 +55,7 @@ internal class PhoneNumberRetrieveResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -83,6 +85,7 @@ internal class PhoneNumberRetrieveResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateResponseTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateResponseTest.kt index e884d30..598b544 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateResponseTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/models/phonenumbers/PhoneNumberUpdateResponseTest.kt @@ -29,6 +29,7 @@ internal class PhoneNumberUpdateResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -54,6 +55,7 @@ internal class PhoneNumberUpdateResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -83,6 +85,7 @@ internal class PhoneNumberUpdateResponseTest { .upfrontCost(0.0) .build() ) + .regulatoryStatus(OwnedPhoneNumber.RegulatoryStatus.APPROVED) .status(PhoneNumberStatus.ACTIVE) .name("name") .nextRenewalDate(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/AddressServiceAsyncTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/AddressServiceAsyncTest.kt index 4bc7ae1..9cccc63 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/AddressServiceAsyncTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/AddressServiceAsyncTest.kt @@ -19,14 +19,14 @@ internal class AddressServiceAsyncTest { addressServiceAsync.create( AddressCreateParams.builder() .countryCode("DE") + .firstName("John") + .lastName("Doe") .locality("Berlin") .postalCode("10115") .streetAddress("123 Main St") .administrativeArea("administrativeArea") .businessName("businessName") .extendedAddress("extendedAddress") - .firstName("John") - .lastName("Doe") .build() ) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsyncTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsyncTest.kt index 4301a57..3efd27e 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsyncTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/async/PhoneNumberServiceAsyncTest.kt @@ -67,6 +67,13 @@ internal class PhoneNumberServiceAsyncTest { PhoneNumberPurchaseParams.builder() .phoneNumber("+15551234567") .name("Primary Line") + .addRegulatoryRequirement( + PhoneNumberPurchaseParams.RegulatoryRequirement.builder() + .fieldValue("jd7x2k3m4n5p6q7r8s9t0abc") + .requirementType("8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10") + .build() + ) + .type(PhoneNumberType.LOCAL) .build() ) @@ -95,6 +102,7 @@ internal class PhoneNumberServiceAsyncTest { phoneNumberServiceAsync.requirements( PhoneNumberRequirementsParams.builder() .countryCode("xx") + .phoneNumber("phoneNumber") .type(PhoneNumberType.LOCAL) .build() ) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/AddressServiceTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/AddressServiceTest.kt index 66f02d1..bbe09e9 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/AddressServiceTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/AddressServiceTest.kt @@ -19,14 +19,14 @@ internal class AddressServiceTest { addressService.create( AddressCreateParams.builder() .countryCode("DE") + .firstName("John") + .lastName("Doe") .locality("Berlin") .postalCode("10115") .streetAddress("123 Main St") .administrativeArea("administrativeArea") .businessName("businessName") .extendedAddress("extendedAddress") - .firstName("John") - .lastName("Doe") .build() ) diff --git a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/PhoneNumberServiceTest.kt b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/PhoneNumberServiceTest.kt index 5e12212..c451267 100644 --- a/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/PhoneNumberServiceTest.kt +++ b/zavudev-java-core/src/test/kotlin/com/zavudev/api/services/blocking/PhoneNumberServiceTest.kt @@ -64,6 +64,13 @@ internal class PhoneNumberServiceTest { PhoneNumberPurchaseParams.builder() .phoneNumber("+15551234567") .name("Primary Line") + .addRegulatoryRequirement( + PhoneNumberPurchaseParams.RegulatoryRequirement.builder() + .fieldValue("jd7x2k3m4n5p6q7r8s9t0abc") + .requirementType("8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10") + .build() + ) + .type(PhoneNumberType.LOCAL) .build() ) @@ -89,6 +96,7 @@ internal class PhoneNumberServiceTest { phoneNumberService.requirements( PhoneNumberRequirementsParams.builder() .countryCode("xx") + .phoneNumber("phoneNumber") .type(PhoneNumberType.LOCAL) .build() )