diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 90eeef65..6b467676 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "4.8.0"
+ ".": "4.9.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index edd99bd4..17749e26 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 78
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-4469c7d243ac17a71d48187ede11d7f6fd178d1006f2542c973259c5c37007fb.yml
-openapi_spec_hash: 2036a46b6fa7ac8eae981583bd452458
-config_hash: 93eb861d9572cea4d66edeab309e08c6
+configured_endpoints: 81
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-3fc1c86b4a83a16393aaf17d1fb3ac6098d30dd057ba872973b57285a7a3f0d0.yml
+openapi_spec_hash: 02a545d217b13399f311e99561f9de1d
+config_hash: 0789c3cddc625bb9712b3bded274ab6c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 429953fe..5618fa3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+## 4.9.0 (2026-02-06)
+
+Full Changelog: [v4.8.0...v4.9.0](https://github.com/trycourier/courier-java/compare/v4.8.0...v4.9.0)
+
+### Features
+
+* **api:** add publish/replace methods, versions resource to tenant templates ([41fbfe5](https://github.com/trycourier/courier-java/commit/41fbfe5dd327a8a142da5ac65ba72f777f9794a9))
+* **api:** add toOfRecipients method to send message ([35df215](https://github.com/trycourier/courier-java/commit/35df2154e48a5e158285cda871f506202d9199c6))
+
+
+### Chores
+
+* **internal:** allow passing args to `./scripts/test` ([a809582](https://github.com/trycourier/courier-java/commit/a8095821586036d00c3543929e6eef860fabdd3a))
+
## 4.8.0 (2026-01-27)
Full Changelog: [v4.7.1...v4.8.0](https://github.com/trycourier/courier-java/compare/v4.7.1...v4.8.0)
diff --git a/README.md b/README.md
index a85bd3fe..689f7a57 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-[](https://central.sonatype.com/artifact/com.courier/courier-java/4.8.0)
-[](https://javadoc.io/doc/com.courier/courier-java/4.8.0)
+[](https://central.sonatype.com/artifact/com.courier/courier-java/4.9.0)
+[](https://javadoc.io/doc/com.courier/courier-java/4.9.0)
@@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/).
-The REST API documentation can be found on [www.courier.com](https://www.courier.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.courier/courier-java/4.8.0).
+The REST API documentation can be found on [www.courier.com](https://www.courier.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.courier/courier-java/4.9.0).
@@ -24,7 +24,7 @@ The REST API documentation can be found on [www.courier.com](https://www.courier
### Gradle
```kotlin
-implementation("com.courier:courier-java:4.8.0")
+implementation("com.courier:courier-java:4.9.0")
```
### Maven
@@ -33,7 +33,7 @@ implementation("com.courier:courier-java:4.8.0")
com.courier
courier-java
- 4.8.0
+ 4.9.0
```
diff --git a/build.gradle.kts b/build.gradle.kts
index 3e741ebc..ca061824 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,7 +8,7 @@ repositories {
allprojects {
group = "com.courier"
- version = "4.8.0" // x-release-please-version
+ version = "4.9.0" // x-release-please-version
}
subprojects {
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/send/SendMessageParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/send/SendMessageParams.kt
index 80bfc668..db5cea79 100644
--- a/courier-java-core/src/main/kotlin/com/courier/models/send/SendMessageParams.kt
+++ b/courier-java-core/src/main/kotlin/com/courier/models/send/SendMessageParams.kt
@@ -998,6 +998,9 @@ private constructor(
/** Alias for calling [to] with `To.ofWebhookRecipient(webhookRecipient)`. */
fun to(webhookRecipient: WebhookRecipient) = to(To.ofWebhookRecipient(webhookRecipient))
+ /** Alias for calling [to] with `To.ofRecipients(recipients)`. */
+ fun toOfRecipients(recipients: List) = to(To.ofRecipients(recipients))
+
fun additionalProperties(additionalProperties: Map) = apply {
this.additionalProperties.clear()
putAllAdditionalProperties(additionalProperties)
@@ -3743,6 +3746,7 @@ private constructor(
private val msTeamsRecipient: MsTeamsRecipient? = null,
private val pagerdutyRecipient: PagerdutyRecipient? = null,
private val webhookRecipient: WebhookRecipient? = null,
+ private val recipients: List? = null,
private val _json: JsonValue? = null,
) {
@@ -3775,6 +3779,8 @@ private constructor(
fun webhookRecipient(): Optional =
Optional.ofNullable(webhookRecipient)
+ fun recipients(): Optional> = Optional.ofNullable(recipients)
+
fun isUserRecipient(): Boolean = userRecipient != null
fun isAudienceRecipient(): Boolean = audienceRecipient != null
@@ -3791,6 +3797,8 @@ private constructor(
fun isWebhookRecipient(): Boolean = webhookRecipient != null
+ fun isRecipients(): Boolean = recipients != null
+
/** Send to a specific user by user_id, email, phone_number, or list_id */
fun asUserRecipient(): UserRecipient = userRecipient.getOrThrow("userRecipient")
@@ -3820,6 +3828,8 @@ private constructor(
fun asWebhookRecipient(): WebhookRecipient =
webhookRecipient.getOrThrow("webhookRecipient")
+ fun asRecipients(): List = recipients.getOrThrow("recipients")
+
fun _json(): Optional = Optional.ofNullable(_json)
fun accept(visitor: Visitor): T =
@@ -3834,6 +3844,7 @@ private constructor(
pagerdutyRecipient != null ->
visitor.visitPagerdutyRecipient(pagerdutyRecipient)
webhookRecipient != null -> visitor.visitWebhookRecipient(webhookRecipient)
+ recipients != null -> visitor.visitRecipients(recipients)
else -> visitor.unknown(_json)
}
@@ -3881,6 +3892,10 @@ private constructor(
override fun visitWebhookRecipient(webhookRecipient: WebhookRecipient) {
webhookRecipient.validate()
}
+
+ override fun visitRecipients(recipients: List) {
+ recipients.forEach { it.validate() }
+ }
}
)
validated = true
@@ -3930,6 +3945,9 @@ private constructor(
override fun visitWebhookRecipient(webhookRecipient: WebhookRecipient) =
webhookRecipient.validity()
+ override fun visitRecipients(recipients: List) =
+ recipients.sumOf { it.validity().toInt() }
+
override fun unknown(json: JsonValue?) = 0
}
)
@@ -3947,7 +3965,8 @@ private constructor(
slackRecipient == other.slackRecipient &&
msTeamsRecipient == other.msTeamsRecipient &&
pagerdutyRecipient == other.pagerdutyRecipient &&
- webhookRecipient == other.webhookRecipient
+ webhookRecipient == other.webhookRecipient &&
+ recipients == other.recipients
}
override fun hashCode(): Int =
@@ -3960,6 +3979,7 @@ private constructor(
msTeamsRecipient,
pagerdutyRecipient,
webhookRecipient,
+ recipients,
)
override fun toString(): String =
@@ -3972,6 +3992,7 @@ private constructor(
msTeamsRecipient != null -> "To{msTeamsRecipient=$msTeamsRecipient}"
pagerdutyRecipient != null -> "To{pagerdutyRecipient=$pagerdutyRecipient}"
webhookRecipient != null -> "To{webhookRecipient=$webhookRecipient}"
+ recipients != null -> "To{recipients=$recipients}"
_json != null -> "To{_unknown=$_json}"
else -> throw IllegalStateException("Invalid To")
}
@@ -4017,6 +4038,10 @@ private constructor(
@JvmStatic
fun ofWebhookRecipient(webhookRecipient: WebhookRecipient) =
To(webhookRecipient = webhookRecipient)
+
+ @JvmStatic
+ fun ofRecipients(recipients: List) =
+ To(recipients = recipients.toImmutable())
}
/** An interface that defines how to map each variant of [To] to a value of type [T]. */
@@ -4046,6 +4071,8 @@ private constructor(
/** Send via webhook */
fun visitWebhookRecipient(webhookRecipient: WebhookRecipient): T
+ fun visitRecipients(recipients: List): T
+
/**
* Maps an unknown variant of [To] to a value of type [T].
*
@@ -4092,6 +4119,9 @@ private constructor(
tryDeserialize(node, jacksonTypeRef())?.let {
To(webhookRecipient = it, _json = json)
},
+ tryDeserialize(node, jacksonTypeRef>())?.let {
+ To(recipients = it, _json = json)
+ },
)
.filterNotNull()
.allMaxBy { it.validity() }
@@ -4130,11 +4160,394 @@ private constructor(
generator.writeObject(value.pagerdutyRecipient)
value.webhookRecipient != null ->
generator.writeObject(value.webhookRecipient)
+ value.recipients != null -> generator.writeObject(value.recipients)
value._json != null -> generator.writeObject(value._json)
else -> throw IllegalStateException("Invalid To")
}
}
}
+
+ /**
+ * A single recipient of the message. Choose one of the following types based on how you
+ * want to identify the recipient: - **User**: Send to a specific user by user_id,
+ * email, or phone number - **Audience**: Send to all users in an audience - **List**:
+ * Send to all users in a list - **List Pattern**: Send to users in lists matching a
+ * pattern - **Slack**: Send via Slack (channel, email, or user_id) - **MS Teams**: Send
+ * via Microsoft Teams - **PagerDuty**: Send via PagerDuty - **Webhook**: Send via
+ * webhook
+ */
+ @JsonDeserialize(using = Recipient.Deserializer::class)
+ @JsonSerialize(using = Recipient.Serializer::class)
+ class Recipient
+ private constructor(
+ private val user: UserRecipient? = null,
+ private val audience: AudienceRecipient? = null,
+ private val list: ListRecipient? = null,
+ private val listPattern: ListPatternRecipient? = null,
+ private val slack: SlackRecipient? = null,
+ private val msTeams: MsTeamsRecipient? = null,
+ private val pagerduty: PagerdutyRecipient? = null,
+ private val webhook: WebhookRecipient? = null,
+ private val _json: JsonValue? = null,
+ ) {
+
+ /** Send to a specific user by user_id, email, phone_number, or list_id */
+ fun user(): Optional = Optional.ofNullable(user)
+
+ /** Send to all users in an audience */
+ fun audience(): Optional = Optional.ofNullable(audience)
+
+ /** Send to all users in a specific list */
+ fun list(): Optional = Optional.ofNullable(list)
+
+ /** Send to users in lists matching a pattern */
+ fun listPattern(): Optional = Optional.ofNullable(listPattern)
+
+ /** Send via Slack (channel, email, or user_id) */
+ fun slack(): Optional = Optional.ofNullable(slack)
+
+ /** Send via Microsoft Teams */
+ fun msTeams(): Optional = Optional.ofNullable(msTeams)
+
+ /** Send via PagerDuty */
+ fun pagerduty(): Optional = Optional.ofNullable(pagerduty)
+
+ /** Send via webhook */
+ fun webhook(): Optional = Optional.ofNullable(webhook)
+
+ fun isUser(): Boolean = user != null
+
+ fun isAudience(): Boolean = audience != null
+
+ fun isList(): Boolean = list != null
+
+ fun isListPattern(): Boolean = listPattern != null
+
+ fun isSlack(): Boolean = slack != null
+
+ fun isMsTeams(): Boolean = msTeams != null
+
+ fun isPagerduty(): Boolean = pagerduty != null
+
+ fun isWebhook(): Boolean = webhook != null
+
+ /** Send to a specific user by user_id, email, phone_number, or list_id */
+ fun asUser(): UserRecipient = user.getOrThrow("user")
+
+ /** Send to all users in an audience */
+ fun asAudience(): AudienceRecipient = audience.getOrThrow("audience")
+
+ /** Send to all users in a specific list */
+ fun asList(): ListRecipient = list.getOrThrow("list")
+
+ /** Send to users in lists matching a pattern */
+ fun asListPattern(): ListPatternRecipient = listPattern.getOrThrow("listPattern")
+
+ /** Send via Slack (channel, email, or user_id) */
+ fun asSlack(): SlackRecipient = slack.getOrThrow("slack")
+
+ /** Send via Microsoft Teams */
+ fun asMsTeams(): MsTeamsRecipient = msTeams.getOrThrow("msTeams")
+
+ /** Send via PagerDuty */
+ fun asPagerduty(): PagerdutyRecipient = pagerduty.getOrThrow("pagerduty")
+
+ /** Send via webhook */
+ fun asWebhook(): WebhookRecipient = webhook.getOrThrow("webhook")
+
+ fun _json(): Optional = Optional.ofNullable(_json)
+
+ fun accept(visitor: Visitor): T =
+ when {
+ user != null -> visitor.visitUser(user)
+ audience != null -> visitor.visitAudience(audience)
+ list != null -> visitor.visitList(list)
+ listPattern != null -> visitor.visitListPattern(listPattern)
+ slack != null -> visitor.visitSlack(slack)
+ msTeams != null -> visitor.visitMsTeams(msTeams)
+ pagerduty != null -> visitor.visitPagerduty(pagerduty)
+ webhook != null -> visitor.visitWebhook(webhook)
+ else -> visitor.unknown(_json)
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Recipient = apply {
+ if (validated) {
+ return@apply
+ }
+
+ accept(
+ object : Visitor {
+ override fun visitUser(user: UserRecipient) {
+ user.validate()
+ }
+
+ override fun visitAudience(audience: AudienceRecipient) {
+ audience.validate()
+ }
+
+ override fun visitList(list: ListRecipient) {
+ list.validate()
+ }
+
+ override fun visitListPattern(listPattern: ListPatternRecipient) {
+ listPattern.validate()
+ }
+
+ override fun visitSlack(slack: SlackRecipient) {
+ slack.validate()
+ }
+
+ override fun visitMsTeams(msTeams: MsTeamsRecipient) {
+ msTeams.validate()
+ }
+
+ override fun visitPagerduty(pagerduty: PagerdutyRecipient) {
+ pagerduty.validate()
+ }
+
+ override fun visitWebhook(webhook: WebhookRecipient) {
+ webhook.validate()
+ }
+ }
+ )
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 =
+ accept(
+ object : Visitor {
+ override fun visitUser(user: UserRecipient) = user.validity()
+
+ override fun visitAudience(audience: AudienceRecipient) =
+ audience.validity()
+
+ override fun visitList(list: ListRecipient) = list.validity()
+
+ override fun visitListPattern(listPattern: ListPatternRecipient) =
+ listPattern.validity()
+
+ override fun visitSlack(slack: SlackRecipient) = slack.validity()
+
+ override fun visitMsTeams(msTeams: MsTeamsRecipient) =
+ msTeams.validity()
+
+ override fun visitPagerduty(pagerduty: PagerdutyRecipient) =
+ pagerduty.validity()
+
+ override fun visitWebhook(webhook: WebhookRecipient) =
+ webhook.validity()
+
+ override fun unknown(json: JsonValue?) = 0
+ }
+ )
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Recipient &&
+ user == other.user &&
+ audience == other.audience &&
+ list == other.list &&
+ listPattern == other.listPattern &&
+ slack == other.slack &&
+ msTeams == other.msTeams &&
+ pagerduty == other.pagerduty &&
+ webhook == other.webhook
+ }
+
+ override fun hashCode(): Int =
+ Objects.hash(
+ user,
+ audience,
+ list,
+ listPattern,
+ slack,
+ msTeams,
+ pagerduty,
+ webhook,
+ )
+
+ override fun toString(): String =
+ when {
+ user != null -> "Recipient{user=$user}"
+ audience != null -> "Recipient{audience=$audience}"
+ list != null -> "Recipient{list=$list}"
+ listPattern != null -> "Recipient{listPattern=$listPattern}"
+ slack != null -> "Recipient{slack=$slack}"
+ msTeams != null -> "Recipient{msTeams=$msTeams}"
+ pagerduty != null -> "Recipient{pagerduty=$pagerduty}"
+ webhook != null -> "Recipient{webhook=$webhook}"
+ _json != null -> "Recipient{_unknown=$_json}"
+ else -> throw IllegalStateException("Invalid Recipient")
+ }
+
+ companion object {
+
+ /** Send to a specific user by user_id, email, phone_number, or list_id */
+ @JvmStatic fun ofUser(user: UserRecipient) = Recipient(user = user)
+
+ /** Send to all users in an audience */
+ @JvmStatic
+ fun ofAudience(audience: AudienceRecipient) = Recipient(audience = audience)
+
+ /** Send to all users in a specific list */
+ @JvmStatic fun ofList(list: ListRecipient) = Recipient(list = list)
+
+ /** Send to users in lists matching a pattern */
+ @JvmStatic
+ fun ofListPattern(listPattern: ListPatternRecipient) =
+ Recipient(listPattern = listPattern)
+
+ /** Send via Slack (channel, email, or user_id) */
+ @JvmStatic fun ofSlack(slack: SlackRecipient) = Recipient(slack = slack)
+
+ /** Send via Microsoft Teams */
+ @JvmStatic
+ fun ofMsTeams(msTeams: MsTeamsRecipient) = Recipient(msTeams = msTeams)
+
+ /** Send via PagerDuty */
+ @JvmStatic
+ fun ofPagerduty(pagerduty: PagerdutyRecipient) =
+ Recipient(pagerduty = pagerduty)
+
+ /** Send via webhook */
+ @JvmStatic
+ fun ofWebhook(webhook: WebhookRecipient) = Recipient(webhook = webhook)
+ }
+
+ /**
+ * An interface that defines how to map each variant of [Recipient] to a value of
+ * type [T].
+ */
+ interface Visitor {
+
+ /** Send to a specific user by user_id, email, phone_number, or list_id */
+ fun visitUser(user: UserRecipient): T
+
+ /** Send to all users in an audience */
+ fun visitAudience(audience: AudienceRecipient): T
+
+ /** Send to all users in a specific list */
+ fun visitList(list: ListRecipient): T
+
+ /** Send to users in lists matching a pattern */
+ fun visitListPattern(listPattern: ListPatternRecipient): T
+
+ /** Send via Slack (channel, email, or user_id) */
+ fun visitSlack(slack: SlackRecipient): T
+
+ /** Send via Microsoft Teams */
+ fun visitMsTeams(msTeams: MsTeamsRecipient): T
+
+ /** Send via PagerDuty */
+ fun visitPagerduty(pagerduty: PagerdutyRecipient): T
+
+ /** Send via webhook */
+ fun visitWebhook(webhook: WebhookRecipient): T
+
+ /**
+ * Maps an unknown variant of [Recipient] to a value of type [T].
+ *
+ * An instance of [Recipient] can contain an unknown variant if it was
+ * deserialized from data that doesn't match any known variant. For example, if
+ * the SDK is on an older version than the API, then the API may respond with
+ * new variants that the SDK is unaware of.
+ *
+ * @throws CourierInvalidDataException in the default implementation.
+ */
+ fun unknown(json: JsonValue?): T {
+ throw CourierInvalidDataException("Unknown Recipient: $json")
+ }
+ }
+
+ internal class Deserializer : BaseDeserializer(Recipient::class) {
+
+ override fun ObjectCodec.deserialize(node: JsonNode): Recipient {
+ val json = JsonValue.fromJsonNode(node)
+
+ val bestMatches =
+ sequenceOf(
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(user = it, _json = json)
+ },
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(audience = it, _json = json)
+ },
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(list = it, _json = json)
+ },
+ tryDeserialize(node, jacksonTypeRef())
+ ?.let { Recipient(listPattern = it, _json = json) },
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(slack = it, _json = json)
+ },
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(msTeams = it, _json = json)
+ },
+ tryDeserialize(node, jacksonTypeRef())
+ ?.let { Recipient(pagerduty = it, _json = json) },
+ tryDeserialize(node, jacksonTypeRef())?.let {
+ Recipient(webhook = it, _json = json)
+ },
+ )
+ .filterNotNull()
+ .allMaxBy { it.validity() }
+ .toList()
+ return when (bestMatches.size) {
+ // This can happen if what we're deserializing is completely
+ // incompatible with all the possible variants (e.g. deserializing from
+ // boolean).
+ 0 -> Recipient(_json = json)
+ 1 -> bestMatches.single()
+ // If there's more than one match with the highest validity, then use
+ // the first completely valid match, or simply the first match if none
+ // are completely valid.
+ else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first()
+ }
+ }
+ }
+
+ internal class Serializer : BaseSerializer(Recipient::class) {
+
+ override fun serialize(
+ value: Recipient,
+ generator: JsonGenerator,
+ provider: SerializerProvider,
+ ) {
+ when {
+ value.user != null -> generator.writeObject(value.user)
+ value.audience != null -> generator.writeObject(value.audience)
+ value.list != null -> generator.writeObject(value.list)
+ value.listPattern != null -> generator.writeObject(value.listPattern)
+ value.slack != null -> generator.writeObject(value.slack)
+ value.msTeams != null -> generator.writeObject(value.msTeams)
+ value.pagerduty != null -> generator.writeObject(value.pagerduty)
+ value.webhook != null -> generator.writeObject(value.webhook)
+ value._json != null -> generator.writeObject(value._json)
+ else -> throw IllegalStateException("Invalid Recipient")
+ }
+ }
+ }
+ }
}
override fun equals(other: Any?): Boolean {
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishRequest.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishRequest.kt
new file mode 100644
index 00000000..a6d1d9f3
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishRequest.kt
@@ -0,0 +1,166 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants
+
+import com.courier.core.ExcludeMissing
+import com.courier.core.JsonField
+import com.courier.core.JsonMissing
+import com.courier.core.JsonValue
+import com.courier.errors.CourierInvalidDataException
+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 java.util.Collections
+import java.util.Objects
+import java.util.Optional
+
+/** Request body for publishing a tenant template version */
+class PostTenantTemplatePublishRequest
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
+private constructor(
+ private val version: JsonField,
+ private val additionalProperties: MutableMap,
+) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of()
+ ) : this(version, mutableMapOf())
+
+ /**
+ * The version of the template to publish (e.g., "v1", "v2", "latest"). If not provided,
+ * defaults to "latest".
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun version(): Optional = version.getOptional("version")
+
+ /**
+ * Returns the raw JSON value of [version].
+ *
+ * Unlike [version], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version
+
+ @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
+ * [PostTenantTemplatePublishRequest].
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [PostTenantTemplatePublishRequest]. */
+ class Builder internal constructor() {
+
+ private var version: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(postTenantTemplatePublishRequest: PostTenantTemplatePublishRequest) =
+ apply {
+ version = postTenantTemplatePublishRequest.version
+ additionalProperties =
+ postTenantTemplatePublishRequest.additionalProperties.toMutableMap()
+ }
+
+ /**
+ * The version of the template to publish (e.g., "v1", "v2", "latest"). If not provided,
+ * defaults to "latest".
+ */
+ fun version(version: String) = version(JsonField.of(version))
+
+ /**
+ * Sets [Builder.version] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.version] with a well-typed [String] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun version(version: JsonField) = apply { this.version = version }
+
+ 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 [PostTenantTemplatePublishRequest].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): PostTenantTemplatePublishRequest =
+ PostTenantTemplatePublishRequest(version, additionalProperties.toMutableMap())
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): PostTenantTemplatePublishRequest = apply {
+ if (validated) {
+ return@apply
+ }
+
+ version()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 (version.asKnown().isPresent) 1 else 0)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is PostTenantTemplatePublishRequest &&
+ version == other.version &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy { Objects.hash(version, additionalProperties) }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "PostTenantTemplatePublishRequest{version=$version, additionalProperties=$additionalProperties}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishResponse.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishResponse.kt
new file mode 100644
index 00000000..b85d08cb
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PostTenantTemplatePublishResponse.kt
@@ -0,0 +1,258 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants
+
+import com.courier.core.ExcludeMissing
+import com.courier.core.JsonField
+import com.courier.core.JsonMissing
+import com.courier.core.JsonValue
+import com.courier.core.checkRequired
+import com.courier.errors.CourierInvalidDataException
+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 java.util.Collections
+import java.util.Objects
+
+/** Response from publishing a tenant template */
+class PostTenantTemplatePublishResponse
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
+private constructor(
+ private val id: JsonField,
+ private val publishedAt: JsonField,
+ private val version: JsonField,
+ private val additionalProperties: MutableMap,
+) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(),
+ @JsonProperty("published_at")
+ @ExcludeMissing
+ publishedAt: JsonField = JsonMissing.of(),
+ @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(),
+ ) : this(id, publishedAt, version, mutableMapOf())
+
+ /**
+ * The template ID
+ *
+ * @throws CourierInvalidDataException 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 id(): String = id.getRequired("id")
+
+ /**
+ * The timestamp when the template was published
+ *
+ * @throws CourierInvalidDataException 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 publishedAt(): String = publishedAt.getRequired("published_at")
+
+ /**
+ * The published version of the template
+ *
+ * @throws CourierInvalidDataException 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 version(): String = version.getRequired("version")
+
+ /**
+ * Returns the raw JSON value of [id].
+ *
+ * Unlike [id], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id
+
+ /**
+ * Returns the raw JSON value of [publishedAt].
+ *
+ * Unlike [publishedAt], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("published_at")
+ @ExcludeMissing
+ fun _publishedAt(): JsonField = publishedAt
+
+ /**
+ * Returns the raw JSON value of [version].
+ *
+ * Unlike [version], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version
+
+ @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
+ * [PostTenantTemplatePublishResponse].
+ *
+ * The following fields are required:
+ * ```java
+ * .id()
+ * .publishedAt()
+ * .version()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [PostTenantTemplatePublishResponse]. */
+ class Builder internal constructor() {
+
+ private var id: JsonField? = null
+ private var publishedAt: JsonField? = null
+ private var version: JsonField? = null
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(postTenantTemplatePublishResponse: PostTenantTemplatePublishResponse) =
+ apply {
+ id = postTenantTemplatePublishResponse.id
+ publishedAt = postTenantTemplatePublishResponse.publishedAt
+ version = postTenantTemplatePublishResponse.version
+ additionalProperties =
+ postTenantTemplatePublishResponse.additionalProperties.toMutableMap()
+ }
+
+ /** The template ID */
+ fun id(id: String) = id(JsonField.of(id))
+
+ /**
+ * Sets [Builder.id] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.id] with a well-typed [String] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun id(id: JsonField) = apply { this.id = id }
+
+ /** The timestamp when the template was published */
+ fun publishedAt(publishedAt: String) = publishedAt(JsonField.of(publishedAt))
+
+ /**
+ * Sets [Builder.publishedAt] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.publishedAt] with a well-typed [String] value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun publishedAt(publishedAt: JsonField) = apply { this.publishedAt = publishedAt }
+
+ /** The published version of the template */
+ fun version(version: String) = version(JsonField.of(version))
+
+ /**
+ * Sets [Builder.version] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.version] with a well-typed [String] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun version(version: JsonField) = apply { this.version = version }
+
+ 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 [PostTenantTemplatePublishResponse].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .id()
+ * .publishedAt()
+ * .version()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): PostTenantTemplatePublishResponse =
+ PostTenantTemplatePublishResponse(
+ checkRequired("id", id),
+ checkRequired("publishedAt", publishedAt),
+ checkRequired("version", version),
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): PostTenantTemplatePublishResponse = apply {
+ if (validated) {
+ return@apply
+ }
+
+ id()
+ publishedAt()
+ version()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 (id.asKnown().isPresent) 1 else 0) +
+ (if (publishedAt.asKnown().isPresent) 1 else 0) +
+ (if (version.asKnown().isPresent) 1 else 0)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is PostTenantTemplatePublishResponse &&
+ id == other.id &&
+ publishedAt == other.publishedAt &&
+ version == other.version &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(id, publishedAt, version, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "PostTenantTemplatePublishResponse{id=$id, publishedAt=$publishedAt, version=$version, additionalProperties=$additionalProperties}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateRequest.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateRequest.kt
new file mode 100644
index 00000000..c5b21b9e
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateRequest.kt
@@ -0,0 +1,222 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants
+
+import com.courier.core.ExcludeMissing
+import com.courier.core.JsonField
+import com.courier.core.JsonMissing
+import com.courier.core.JsonValue
+import com.courier.core.checkRequired
+import com.courier.errors.CourierInvalidDataException
+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 java.util.Collections
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/** Request body for creating or updating a tenant notification template */
+class PutTenantTemplateRequest
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
+private constructor(
+ private val template: JsonField,
+ private val published: JsonField,
+ private val additionalProperties: MutableMap,
+) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("template")
+ @ExcludeMissing
+ template: JsonField = JsonMissing.of(),
+ @JsonProperty("published") @ExcludeMissing published: JsonField = JsonMissing.of(),
+ ) : this(template, published, mutableMapOf())
+
+ /**
+ * Template configuration for creating or updating a tenant notification template
+ *
+ * @throws CourierInvalidDataException 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 template(): TenantTemplateInput = template.getRequired("template")
+
+ /**
+ * Whether to publish the template immediately after saving. When true, the template becomes the
+ * active/published version. When false (default), the template is saved as a draft.
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun published(): Optional = published.getOptional("published")
+
+ /**
+ * Returns the raw JSON value of [template].
+ *
+ * Unlike [template], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("template")
+ @ExcludeMissing
+ fun _template(): JsonField = template
+
+ /**
+ * Returns the raw JSON value of [published].
+ *
+ * Unlike [published], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("published") @ExcludeMissing fun _published(): JsonField = published
+
+ @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 [PutTenantTemplateRequest].
+ *
+ * The following fields are required:
+ * ```java
+ * .template()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [PutTenantTemplateRequest]. */
+ class Builder internal constructor() {
+
+ private var template: JsonField? = null
+ private var published: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(putTenantTemplateRequest: PutTenantTemplateRequest) = apply {
+ template = putTenantTemplateRequest.template
+ published = putTenantTemplateRequest.published
+ additionalProperties = putTenantTemplateRequest.additionalProperties.toMutableMap()
+ }
+
+ /** Template configuration for creating or updating a tenant notification template */
+ fun template(template: TenantTemplateInput) = template(JsonField.of(template))
+
+ /**
+ * Sets [Builder.template] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.template] with a well-typed [TenantTemplateInput] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun template(template: JsonField) = apply { this.template = template }
+
+ /**
+ * Whether to publish the template immediately after saving. When true, the template becomes
+ * the active/published version. When false (default), the template is saved as a draft.
+ */
+ fun published(published: Boolean) = published(JsonField.of(published))
+
+ /**
+ * Sets [Builder.published] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.published] with a well-typed [Boolean] value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun published(published: JsonField) = apply { this.published = published }
+
+ 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 [PutTenantTemplateRequest].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .template()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): PutTenantTemplateRequest =
+ PutTenantTemplateRequest(
+ checkRequired("template", template),
+ published,
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): PutTenantTemplateRequest = apply {
+ if (validated) {
+ return@apply
+ }
+
+ template().validate()
+ published()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 =
+ (template.asKnown().getOrNull()?.validity() ?: 0) +
+ (if (published.asKnown().isPresent) 1 else 0)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is PutTenantTemplateRequest &&
+ template == other.template &&
+ published == other.published &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy { Objects.hash(template, published, additionalProperties) }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "PutTenantTemplateRequest{template=$template, published=$published, additionalProperties=$additionalProperties}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateResponse.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateResponse.kt
new file mode 100644
index 00000000..dd002065
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/PutTenantTemplateResponse.kt
@@ -0,0 +1,262 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants
+
+import com.courier.core.ExcludeMissing
+import com.courier.core.JsonField
+import com.courier.core.JsonMissing
+import com.courier.core.JsonValue
+import com.courier.core.checkRequired
+import com.courier.errors.CourierInvalidDataException
+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 java.util.Collections
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/** Response from creating or updating a tenant notification template */
+class PutTenantTemplateResponse
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
+private constructor(
+ private val id: JsonField,
+ private val version: JsonField,
+ private val publishedAt: JsonField,
+ private val additionalProperties: MutableMap,
+) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(),
+ @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(),
+ @JsonProperty("published_at")
+ @ExcludeMissing
+ publishedAt: JsonField = JsonMissing.of(),
+ ) : this(id, version, publishedAt, mutableMapOf())
+
+ /**
+ * The template ID
+ *
+ * @throws CourierInvalidDataException 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 id(): String = id.getRequired("id")
+
+ /**
+ * The version of the saved template
+ *
+ * @throws CourierInvalidDataException 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 version(): String = version.getRequired("version")
+
+ /**
+ * The timestamp when the template was published. Only present if the template was published as
+ * part of this request.
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun publishedAt(): Optional = publishedAt.getOptional("published_at")
+
+ /**
+ * Returns the raw JSON value of [id].
+ *
+ * Unlike [id], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id
+
+ /**
+ * Returns the raw JSON value of [version].
+ *
+ * Unlike [version], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version
+
+ /**
+ * Returns the raw JSON value of [publishedAt].
+ *
+ * Unlike [publishedAt], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("published_at")
+ @ExcludeMissing
+ fun _publishedAt(): JsonField = publishedAt
+
+ @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 [PutTenantTemplateResponse].
+ *
+ * The following fields are required:
+ * ```java
+ * .id()
+ * .version()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [PutTenantTemplateResponse]. */
+ class Builder internal constructor() {
+
+ private var id: JsonField? = null
+ private var version: JsonField? = null
+ private var publishedAt: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(putTenantTemplateResponse: PutTenantTemplateResponse) = apply {
+ id = putTenantTemplateResponse.id
+ version = putTenantTemplateResponse.version
+ publishedAt = putTenantTemplateResponse.publishedAt
+ additionalProperties = putTenantTemplateResponse.additionalProperties.toMutableMap()
+ }
+
+ /** The template ID */
+ fun id(id: String) = id(JsonField.of(id))
+
+ /**
+ * Sets [Builder.id] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.id] with a well-typed [String] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun id(id: JsonField) = apply { this.id = id }
+
+ /** The version of the saved template */
+ fun version(version: String) = version(JsonField.of(version))
+
+ /**
+ * Sets [Builder.version] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.version] with a well-typed [String] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun version(version: JsonField) = apply { this.version = version }
+
+ /**
+ * The timestamp when the template was published. Only present if the template was published
+ * as part of this request.
+ */
+ fun publishedAt(publishedAt: String?) = publishedAt(JsonField.ofNullable(publishedAt))
+
+ /** Alias for calling [Builder.publishedAt] with `publishedAt.orElse(null)`. */
+ fun publishedAt(publishedAt: Optional) = publishedAt(publishedAt.getOrNull())
+
+ /**
+ * Sets [Builder.publishedAt] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.publishedAt] with a well-typed [String] value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun publishedAt(publishedAt: JsonField) = apply { this.publishedAt = publishedAt }
+
+ 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 [PutTenantTemplateResponse].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .id()
+ * .version()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): PutTenantTemplateResponse =
+ PutTenantTemplateResponse(
+ checkRequired("id", id),
+ checkRequired("version", version),
+ publishedAt,
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): PutTenantTemplateResponse = apply {
+ if (validated) {
+ return@apply
+ }
+
+ id()
+ version()
+ publishedAt()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 (id.asKnown().isPresent) 1 else 0) +
+ (if (version.asKnown().isPresent) 1 else 0) +
+ (if (publishedAt.asKnown().isPresent) 1 else 0)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is PutTenantTemplateResponse &&
+ id == other.id &&
+ version == other.version &&
+ publishedAt == other.publishedAt &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(id, version, publishedAt, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "PutTenantTemplateResponse{id=$id, version=$version, publishedAt=$publishedAt, additionalProperties=$additionalProperties}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/TenantTemplateInput.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/TenantTemplateInput.kt
new file mode 100644
index 00000000..4570b92f
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/TenantTemplateInput.kt
@@ -0,0 +1,495 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants
+
+import com.courier.core.ExcludeMissing
+import com.courier.core.JsonField
+import com.courier.core.JsonMissing
+import com.courier.core.JsonValue
+import com.courier.core.checkRequired
+import com.courier.core.toImmutable
+import com.courier.errors.CourierInvalidDataException
+import com.courier.models.ElementalContent
+import com.courier.models.MessageRouting
+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 java.util.Collections
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/** Template configuration for creating or updating a tenant notification template */
+class TenantTemplateInput
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
+private constructor(
+ private val content: JsonField,
+ private val channels: JsonField,
+ private val providers: JsonField,
+ private val routing: JsonField,
+ private val additionalProperties: MutableMap,
+) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("content")
+ @ExcludeMissing
+ content: JsonField = JsonMissing.of(),
+ @JsonProperty("channels") @ExcludeMissing channels: JsonField = JsonMissing.of(),
+ @JsonProperty("providers")
+ @ExcludeMissing
+ providers: JsonField = JsonMissing.of(),
+ @JsonProperty("routing")
+ @ExcludeMissing
+ routing: JsonField = JsonMissing.of(),
+ ) : this(content, channels, providers, routing, mutableMapOf())
+
+ /**
+ * Template content configuration including blocks, elements, and message structure
+ *
+ * @throws CourierInvalidDataException 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 content(): ElementalContent = content.getRequired("content")
+
+ /**
+ * Channel-specific delivery configuration (email, SMS, push, etc.)
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun channels(): Optional = channels.getOptional("channels")
+
+ /**
+ * Provider-specific delivery configuration for routing to specific email/SMS providers
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun providers(): Optional = providers.getOptional("providers")
+
+ /**
+ * Message routing configuration for multi-channel delivery strategies
+ *
+ * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun routing(): Optional = routing.getOptional("routing")
+
+ /**
+ * Returns the raw JSON value of [content].
+ *
+ * Unlike [content], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content
+
+ /**
+ * Returns the raw JSON value of [channels].
+ *
+ * Unlike [channels], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("channels") @ExcludeMissing fun _channels(): JsonField = channels
+
+ /**
+ * Returns the raw JSON value of [providers].
+ *
+ * Unlike [providers], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("providers") @ExcludeMissing fun _providers(): JsonField = providers
+
+ /**
+ * Returns the raw JSON value of [routing].
+ *
+ * Unlike [routing], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("routing") @ExcludeMissing fun _routing(): JsonField = routing
+
+ @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 [TenantTemplateInput].
+ *
+ * The following fields are required:
+ * ```java
+ * .content()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [TenantTemplateInput]. */
+ class Builder internal constructor() {
+
+ private var content: JsonField? = null
+ private var channels: JsonField = JsonMissing.of()
+ private var providers: JsonField = JsonMissing.of()
+ private var routing: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(tenantTemplateInput: TenantTemplateInput) = apply {
+ content = tenantTemplateInput.content
+ channels = tenantTemplateInput.channels
+ providers = tenantTemplateInput.providers
+ routing = tenantTemplateInput.routing
+ additionalProperties = tenantTemplateInput.additionalProperties.toMutableMap()
+ }
+
+ /** Template content configuration including blocks, elements, and message structure */
+ fun content(content: ElementalContent) = content(JsonField.of(content))
+
+ /**
+ * Sets [Builder.content] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.content] with a well-typed [ElementalContent] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun content(content: JsonField) = apply { this.content = content }
+
+ /** Channel-specific delivery configuration (email, SMS, push, etc.) */
+ fun channels(channels: Channels) = channels(JsonField.of(channels))
+
+ /**
+ * Sets [Builder.channels] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.channels] with a well-typed [Channels] value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun channels(channels: JsonField) = apply { this.channels = channels }
+
+ /** Provider-specific delivery configuration for routing to specific email/SMS providers */
+ fun providers(providers: Providers) = providers(JsonField.of(providers))
+
+ /**
+ * Sets [Builder.providers] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.providers] with a well-typed [Providers] value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun providers(providers: JsonField) = apply { this.providers = providers }
+
+ /** Message routing configuration for multi-channel delivery strategies */
+ fun routing(routing: MessageRouting) = routing(JsonField.of(routing))
+
+ /**
+ * Sets [Builder.routing] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.routing] with a well-typed [MessageRouting] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun routing(routing: JsonField) = apply { this.routing = routing }
+
+ 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 [TenantTemplateInput].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .content()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): TenantTemplateInput =
+ TenantTemplateInput(
+ checkRequired("content", content),
+ channels,
+ providers,
+ routing,
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): TenantTemplateInput = apply {
+ if (validated) {
+ return@apply
+ }
+
+ content().validate()
+ channels().ifPresent { it.validate() }
+ providers().ifPresent { it.validate() }
+ routing().ifPresent { it.validate() }
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 =
+ (content.asKnown().getOrNull()?.validity() ?: 0) +
+ (channels.asKnown().getOrNull()?.validity() ?: 0) +
+ (providers.asKnown().getOrNull()?.validity() ?: 0) +
+ (routing.asKnown().getOrNull()?.validity() ?: 0)
+
+ /** Channel-specific delivery configuration (email, SMS, push, etc.) */
+ class Channels
+ @JsonCreator
+ private constructor(
+ @com.fasterxml.jackson.annotation.JsonValue
+ private val additionalProperties: Map
+ ) {
+
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map = additionalProperties
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /** Returns a mutable builder for constructing an instance of [Channels]. */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Channels]. */
+ class Builder internal constructor() {
+
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(channels: Channels) = apply {
+ additionalProperties = channels.additionalProperties.toMutableMap()
+ }
+
+ 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 [Channels].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): Channels = Channels(additionalProperties.toImmutable())
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Channels = apply {
+ if (validated) {
+ return@apply
+ }
+
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 =
+ additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Channels && additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy { Objects.hash(additionalProperties) }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() = "Channels{additionalProperties=$additionalProperties}"
+ }
+
+ /** Provider-specific delivery configuration for routing to specific email/SMS providers */
+ class Providers
+ @JsonCreator
+ private constructor(
+ @com.fasterxml.jackson.annotation.JsonValue
+ private val additionalProperties: Map
+ ) {
+
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map = additionalProperties
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /** Returns a mutable builder for constructing an instance of [Providers]. */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Providers]. */
+ class Builder internal constructor() {
+
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(providers: Providers) = apply {
+ additionalProperties = providers.additionalProperties.toMutableMap()
+ }
+
+ 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 [Providers].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): Providers = Providers(additionalProperties.toImmutable())
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Providers = apply {
+ if (validated) {
+ return@apply
+ }
+
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CourierInvalidDataException) {
+ 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 =
+ additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Providers && additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy { Objects.hash(additionalProperties) }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() = "Providers{additionalProperties=$additionalProperties}"
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is TenantTemplateInput &&
+ content == other.content &&
+ channels == other.channels &&
+ providers == other.providers &&
+ routing == other.routing &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(content, channels, providers, routing, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "TenantTemplateInput{content=$content, channels=$channels, providers=$providers, routing=$routing, additionalProperties=$additionalProperties}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplatePublishParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplatePublishParams.kt
new file mode 100644
index 00000000..2c74d73a
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplatePublishParams.kt
@@ -0,0 +1,260 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants.templates
+
+import com.courier.core.JsonValue
+import com.courier.core.Params
+import com.courier.core.checkRequired
+import com.courier.core.http.Headers
+import com.courier.core.http.QueryParams
+import com.courier.core.immutableEmptyMap
+import com.courier.models.tenants.PostTenantTemplatePublishRequest
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/**
+ * Publishes a specific version of a notification template for a tenant.
+ *
+ * The template must already exist in the tenant's notification map. If no version is specified,
+ * defaults to publishing the "latest" version.
+ */
+class TemplatePublishParams
+private constructor(
+ private val tenantId: String,
+ private val templateId: String?,
+ private val postTenantTemplatePublishRequest: PostTenantTemplatePublishRequest?,
+ private val additionalHeaders: Headers,
+ private val additionalQueryParams: QueryParams,
+) : Params {
+
+ fun tenantId(): String = tenantId
+
+ fun templateId(): Optional = Optional.ofNullable(templateId)
+
+ /** Request body for publishing a tenant template version */
+ fun postTenantTemplatePublishRequest(): Optional =
+ Optional.ofNullable(postTenantTemplatePublishRequest)
+
+ fun _additionalBodyProperties(): Map =
+ postTenantTemplatePublishRequest?._additionalProperties() ?: immutableEmptyMap()
+
+ /** Additional headers to send with the request. */
+ fun _additionalHeaders(): Headers = additionalHeaders
+
+ /** Additional query param to send with the request. */
+ fun _additionalQueryParams(): QueryParams = additionalQueryParams
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [TemplatePublishParams].
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [TemplatePublishParams]. */
+ class Builder internal constructor() {
+
+ private var tenantId: String? = null
+ private var templateId: String? = null
+ private var postTenantTemplatePublishRequest: PostTenantTemplatePublishRequest? = null
+ private var additionalHeaders: Headers.Builder = Headers.builder()
+ private var additionalQueryParams: QueryParams.Builder = QueryParams.builder()
+
+ @JvmSynthetic
+ internal fun from(templatePublishParams: TemplatePublishParams) = apply {
+ tenantId = templatePublishParams.tenantId
+ templateId = templatePublishParams.templateId
+ postTenantTemplatePublishRequest =
+ templatePublishParams.postTenantTemplatePublishRequest
+ additionalHeaders = templatePublishParams.additionalHeaders.toBuilder()
+ additionalQueryParams = templatePublishParams.additionalQueryParams.toBuilder()
+ }
+
+ fun tenantId(tenantId: String) = apply { this.tenantId = tenantId }
+
+ fun templateId(templateId: String?) = apply { this.templateId = templateId }
+
+ /** Alias for calling [Builder.templateId] with `templateId.orElse(null)`. */
+ fun templateId(templateId: Optional) = templateId(templateId.getOrNull())
+
+ /** Request body for publishing a tenant template version */
+ fun postTenantTemplatePublishRequest(
+ postTenantTemplatePublishRequest: PostTenantTemplatePublishRequest?
+ ) = apply { this.postTenantTemplatePublishRequest = postTenantTemplatePublishRequest }
+
+ /**
+ * Alias for calling [Builder.postTenantTemplatePublishRequest] with
+ * `postTenantTemplatePublishRequest.orElse(null)`.
+ */
+ fun postTenantTemplatePublishRequest(
+ postTenantTemplatePublishRequest: Optional
+ ) = postTenantTemplatePublishRequest(postTenantTemplatePublishRequest.getOrNull())
+
+ fun additionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun additionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun putAdditionalHeader(name: String, value: String) = apply {
+ additionalHeaders.put(name, value)
+ }
+
+ fun putAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.put(name, values)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun replaceAdditionalHeaders(name: String, value: String) = apply {
+ additionalHeaders.replace(name, value)
+ }
+
+ fun replaceAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.replace(name, values)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) }
+
+ fun removeAllAdditionalHeaders(names: Set) = apply {
+ additionalHeaders.removeAll(names)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: Map>) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun putAdditionalQueryParam(key: String, value: String) = apply {
+ additionalQueryParams.put(key, value)
+ }
+
+ fun putAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.put(key, values)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, value: String) = apply {
+ additionalQueryParams.replace(key, value)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.replace(key, values)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) }
+
+ fun removeAllAdditionalQueryParams(keys: Set) = apply {
+ additionalQueryParams.removeAll(keys)
+ }
+
+ /**
+ * Returns an immutable instance of [TemplatePublishParams].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): TemplatePublishParams =
+ TemplatePublishParams(
+ checkRequired("tenantId", tenantId),
+ templateId,
+ postTenantTemplatePublishRequest,
+ additionalHeaders.build(),
+ additionalQueryParams.build(),
+ )
+ }
+
+ fun _body(): Optional =
+ Optional.ofNullable(postTenantTemplatePublishRequest)
+
+ fun _pathParam(index: Int): String =
+ when (index) {
+ 0 -> tenantId
+ 1 -> templateId ?: ""
+ else -> ""
+ }
+
+ override fun _headers(): Headers = additionalHeaders
+
+ override fun _queryParams(): QueryParams = additionalQueryParams
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is TemplatePublishParams &&
+ tenantId == other.tenantId &&
+ templateId == other.templateId &&
+ postTenantTemplatePublishRequest == other.postTenantTemplatePublishRequest &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
+ }
+
+ override fun hashCode(): Int =
+ Objects.hash(
+ tenantId,
+ templateId,
+ postTenantTemplatePublishRequest,
+ additionalHeaders,
+ additionalQueryParams,
+ )
+
+ override fun toString() =
+ "TemplatePublishParams{tenantId=$tenantId, templateId=$templateId, postTenantTemplatePublishRequest=$postTenantTemplatePublishRequest, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplateReplaceParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplateReplaceParams.kt
new file mode 100644
index 00000000..a787cfc6
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/TemplateReplaceParams.kt
@@ -0,0 +1,252 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants.templates
+
+import com.courier.core.JsonValue
+import com.courier.core.Params
+import com.courier.core.checkRequired
+import com.courier.core.http.Headers
+import com.courier.core.http.QueryParams
+import com.courier.models.tenants.PutTenantTemplateRequest
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/**
+ * Creates or updates a notification template for a tenant.
+ *
+ * If the template already exists for the tenant, it will be updated (200). Otherwise, a new
+ * template is created (201).
+ *
+ * Optionally publishes the template immediately if the `published` flag is set to true.
+ */
+class TemplateReplaceParams
+private constructor(
+ private val tenantId: String,
+ private val templateId: String?,
+ private val putTenantTemplateRequest: PutTenantTemplateRequest,
+ private val additionalHeaders: Headers,
+ private val additionalQueryParams: QueryParams,
+) : Params {
+
+ fun tenantId(): String = tenantId
+
+ fun templateId(): Optional = Optional.ofNullable(templateId)
+
+ /** Request body for creating or updating a tenant notification template */
+ fun putTenantTemplateRequest(): PutTenantTemplateRequest = putTenantTemplateRequest
+
+ fun _additionalBodyProperties(): Map =
+ putTenantTemplateRequest._additionalProperties()
+
+ /** Additional headers to send with the request. */
+ fun _additionalHeaders(): Headers = additionalHeaders
+
+ /** Additional query param to send with the request. */
+ fun _additionalQueryParams(): QueryParams = additionalQueryParams
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [TemplateReplaceParams].
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * .putTenantTemplateRequest()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [TemplateReplaceParams]. */
+ class Builder internal constructor() {
+
+ private var tenantId: String? = null
+ private var templateId: String? = null
+ private var putTenantTemplateRequest: PutTenantTemplateRequest? = null
+ private var additionalHeaders: Headers.Builder = Headers.builder()
+ private var additionalQueryParams: QueryParams.Builder = QueryParams.builder()
+
+ @JvmSynthetic
+ internal fun from(templateReplaceParams: TemplateReplaceParams) = apply {
+ tenantId = templateReplaceParams.tenantId
+ templateId = templateReplaceParams.templateId
+ putTenantTemplateRequest = templateReplaceParams.putTenantTemplateRequest
+ additionalHeaders = templateReplaceParams.additionalHeaders.toBuilder()
+ additionalQueryParams = templateReplaceParams.additionalQueryParams.toBuilder()
+ }
+
+ fun tenantId(tenantId: String) = apply { this.tenantId = tenantId }
+
+ fun templateId(templateId: String?) = apply { this.templateId = templateId }
+
+ /** Alias for calling [Builder.templateId] with `templateId.orElse(null)`. */
+ fun templateId(templateId: Optional) = templateId(templateId.getOrNull())
+
+ /** Request body for creating or updating a tenant notification template */
+ fun putTenantTemplateRequest(putTenantTemplateRequest: PutTenantTemplateRequest) = apply {
+ this.putTenantTemplateRequest = putTenantTemplateRequest
+ }
+
+ fun additionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun additionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun putAdditionalHeader(name: String, value: String) = apply {
+ additionalHeaders.put(name, value)
+ }
+
+ fun putAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.put(name, values)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun replaceAdditionalHeaders(name: String, value: String) = apply {
+ additionalHeaders.replace(name, value)
+ }
+
+ fun replaceAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.replace(name, values)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) }
+
+ fun removeAllAdditionalHeaders(names: Set) = apply {
+ additionalHeaders.removeAll(names)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: Map>) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun putAdditionalQueryParam(key: String, value: String) = apply {
+ additionalQueryParams.put(key, value)
+ }
+
+ fun putAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.put(key, values)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, value: String) = apply {
+ additionalQueryParams.replace(key, value)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.replace(key, values)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) }
+
+ fun removeAllAdditionalQueryParams(keys: Set) = apply {
+ additionalQueryParams.removeAll(keys)
+ }
+
+ /**
+ * Returns an immutable instance of [TemplateReplaceParams].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * .putTenantTemplateRequest()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): TemplateReplaceParams =
+ TemplateReplaceParams(
+ checkRequired("tenantId", tenantId),
+ templateId,
+ checkRequired("putTenantTemplateRequest", putTenantTemplateRequest),
+ additionalHeaders.build(),
+ additionalQueryParams.build(),
+ )
+ }
+
+ fun _body(): PutTenantTemplateRequest = putTenantTemplateRequest
+
+ fun _pathParam(index: Int): String =
+ when (index) {
+ 0 -> tenantId
+ 1 -> templateId ?: ""
+ else -> ""
+ }
+
+ override fun _headers(): Headers = additionalHeaders
+
+ override fun _queryParams(): QueryParams = additionalQueryParams
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is TemplateReplaceParams &&
+ tenantId == other.tenantId &&
+ templateId == other.templateId &&
+ putTenantTemplateRequest == other.putTenantTemplateRequest &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
+ }
+
+ override fun hashCode(): Int =
+ Objects.hash(
+ tenantId,
+ templateId,
+ putTenantTemplateRequest,
+ additionalHeaders,
+ additionalQueryParams,
+ )
+
+ override fun toString() =
+ "TemplateReplaceParams{tenantId=$tenantId, templateId=$templateId, putTenantTemplateRequest=$putTenantTemplateRequest, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/versions/VersionRetrieveParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/versions/VersionRetrieveParams.kt
new file mode 100644
index 00000000..194d20d4
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/models/tenants/templates/versions/VersionRetrieveParams.kt
@@ -0,0 +1,236 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.models.tenants.templates.versions
+
+import com.courier.core.Params
+import com.courier.core.checkRequired
+import com.courier.core.http.Headers
+import com.courier.core.http.QueryParams
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/**
+ * Fetches a specific version of a tenant template.
+ *
+ * Supports the following version formats:
+ * - `latest` - The most recent version of the template
+ * - `published` - The currently published version
+ * - `v{version}` - A specific version (e.g., "v1", "v2", "v1.0.0")
+ */
+class VersionRetrieveParams
+private constructor(
+ private val tenantId: String,
+ private val templateId: String,
+ private val version: String?,
+ private val additionalHeaders: Headers,
+ private val additionalQueryParams: QueryParams,
+) : Params {
+
+ fun tenantId(): String = tenantId
+
+ fun templateId(): String = templateId
+
+ fun version(): Optional = Optional.ofNullable(version)
+
+ /** Additional headers to send with the request. */
+ fun _additionalHeaders(): Headers = additionalHeaders
+
+ /** Additional query param to send with the request. */
+ fun _additionalQueryParams(): QueryParams = additionalQueryParams
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [VersionRetrieveParams].
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * .templateId()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [VersionRetrieveParams]. */
+ class Builder internal constructor() {
+
+ private var tenantId: String? = null
+ private var templateId: String? = null
+ private var version: String? = null
+ private var additionalHeaders: Headers.Builder = Headers.builder()
+ private var additionalQueryParams: QueryParams.Builder = QueryParams.builder()
+
+ @JvmSynthetic
+ internal fun from(versionRetrieveParams: VersionRetrieveParams) = apply {
+ tenantId = versionRetrieveParams.tenantId
+ templateId = versionRetrieveParams.templateId
+ version = versionRetrieveParams.version
+ additionalHeaders = versionRetrieveParams.additionalHeaders.toBuilder()
+ additionalQueryParams = versionRetrieveParams.additionalQueryParams.toBuilder()
+ }
+
+ fun tenantId(tenantId: String) = apply { this.tenantId = tenantId }
+
+ fun templateId(templateId: String) = apply { this.templateId = templateId }
+
+ fun version(version: String?) = apply { this.version = version }
+
+ /** Alias for calling [Builder.version] with `version.orElse(null)`. */
+ fun version(version: Optional) = version(version.getOrNull())
+
+ fun additionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun additionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.clear()
+ putAllAdditionalHeaders(additionalHeaders)
+ }
+
+ fun putAdditionalHeader(name: String, value: String) = apply {
+ additionalHeaders.put(name, value)
+ }
+
+ fun putAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.put(name, values)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.putAll(additionalHeaders)
+ }
+
+ fun replaceAdditionalHeaders(name: String, value: String) = apply {
+ additionalHeaders.replace(name, value)
+ }
+
+ fun replaceAdditionalHeaders(name: String, values: Iterable) = apply {
+ additionalHeaders.replace(name, values)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply {
+ this.additionalHeaders.replaceAll(additionalHeaders)
+ }
+
+ fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) }
+
+ fun removeAllAdditionalHeaders(names: Set) = apply {
+ additionalHeaders.removeAll(names)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun additionalQueryParams(additionalQueryParams: Map>) = apply {
+ this.additionalQueryParams.clear()
+ putAllAdditionalQueryParams(additionalQueryParams)
+ }
+
+ fun putAdditionalQueryParam(key: String, value: String) = apply {
+ additionalQueryParams.put(key, value)
+ }
+
+ fun putAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.put(key, values)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun putAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.putAll(additionalQueryParams)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, value: String) = apply {
+ additionalQueryParams.replace(key, value)
+ }
+
+ fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply {
+ additionalQueryParams.replace(key, values)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) =
+ apply {
+ this.additionalQueryParams.replaceAll(additionalQueryParams)
+ }
+
+ fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) }
+
+ fun removeAllAdditionalQueryParams(keys: Set) = apply {
+ additionalQueryParams.removeAll(keys)
+ }
+
+ /**
+ * Returns an immutable instance of [VersionRetrieveParams].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .tenantId()
+ * .templateId()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): VersionRetrieveParams =
+ VersionRetrieveParams(
+ checkRequired("tenantId", tenantId),
+ checkRequired("templateId", templateId),
+ version,
+ additionalHeaders.build(),
+ additionalQueryParams.build(),
+ )
+ }
+
+ fun _pathParam(index: Int): String =
+ when (index) {
+ 0 -> tenantId
+ 1 -> templateId
+ 2 -> version ?: ""
+ else -> ""
+ }
+
+ override fun _headers(): Headers = additionalHeaders
+
+ override fun _queryParams(): QueryParams = additionalQueryParams
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is VersionRetrieveParams &&
+ tenantId == other.tenantId &&
+ templateId == other.templateId &&
+ version == other.version &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
+ }
+
+ override fun hashCode(): Int =
+ Objects.hash(tenantId, templateId, version, additionalHeaders, additionalQueryParams)
+
+ override fun toString() =
+ "VersionRetrieveParams{tenantId=$tenantId, templateId=$templateId, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsync.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsync.kt
index 115205e6..bb42e1ff 100644
--- a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsync.kt
+++ b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsync.kt
@@ -6,9 +6,14 @@ import com.courier.core.ClientOptions
import com.courier.core.RequestOptions
import com.courier.core.http.HttpResponseFor
import com.courier.models.tenants.BaseTemplateTenantAssociation
+import com.courier.models.tenants.PostTenantTemplatePublishResponse
+import com.courier.models.tenants.PutTenantTemplateResponse
import com.courier.models.tenants.templates.TemplateListParams
import com.courier.models.tenants.templates.TemplateListResponse
+import com.courier.models.tenants.templates.TemplatePublishParams
+import com.courier.models.tenants.templates.TemplateReplaceParams
import com.courier.models.tenants.templates.TemplateRetrieveParams
+import com.courier.services.async.tenants.templates.VersionServiceAsync
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
@@ -26,6 +31,8 @@ interface TemplateServiceAsync {
*/
fun withOptions(modifier: Consumer): TemplateServiceAsync
+ fun versions(): VersionServiceAsync
+
/** Get a Template in Tenant */
fun retrieve(
templateId: String,
@@ -86,6 +93,69 @@ interface TemplateServiceAsync {
): CompletableFuture =
list(tenantId, TemplateListParams.none(), requestOptions)
+ /**
+ * Publishes a specific version of a notification template for a tenant.
+ *
+ * The template must already exist in the tenant's notification map. If no version is specified,
+ * defaults to publishing the "latest" version.
+ */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ ): CompletableFuture =
+ publish(templateId, params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture =
+ publish(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see publish */
+ fun publish(
+ params: TemplatePublishParams
+ ): CompletableFuture = publish(params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture
+
+ /**
+ * Creates or updates a notification template for a tenant.
+ *
+ * If the template already exists for the tenant, it will be updated (200). Otherwise, a new
+ * template is created (201).
+ *
+ * Optionally publishes the template immediately if the `published` flag is set to true.
+ */
+ fun replace(
+ templateId: String,
+ params: TemplateReplaceParams,
+ ): CompletableFuture =
+ replace(templateId, params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ templateId: String,
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture =
+ replace(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see replace */
+ fun replace(params: TemplateReplaceParams): CompletableFuture =
+ replace(params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture
+
/**
* A view of [TemplateServiceAsync] that provides access to raw HTTP responses for each method.
*/
@@ -100,6 +170,8 @@ interface TemplateServiceAsync {
modifier: Consumer
): TemplateServiceAsync.WithRawResponse
+ fun versions(): VersionServiceAsync.WithRawResponse
+
/**
* Returns a raw HTTP response for `get /tenants/{tenant_id}/templates/{template_id}`, but
* is otherwise the same as [TemplateServiceAsync.retrieve].
@@ -170,5 +242,66 @@ interface TemplateServiceAsync {
requestOptions: RequestOptions,
): CompletableFuture> =
list(tenantId, TemplateListParams.none(), requestOptions)
+
+ /**
+ * Returns a raw HTTP response for `post
+ * /tenants/{tenant_id}/templates/{template_id}/publish`, but is otherwise the same as
+ * [TemplateServiceAsync.publish].
+ */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ ): CompletableFuture> =
+ publish(templateId, params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture> =
+ publish(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see publish */
+ fun publish(
+ params: TemplatePublishParams
+ ): CompletableFuture> =
+ publish(params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture>
+
+ /**
+ * Returns a raw HTTP response for `put /tenants/{tenant_id}/templates/{template_id}`, but
+ * is otherwise the same as [TemplateServiceAsync.replace].
+ */
+ fun replace(
+ templateId: String,
+ params: TemplateReplaceParams,
+ ): CompletableFuture> =
+ replace(templateId, params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ templateId: String,
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture> =
+ replace(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see replace */
+ fun replace(
+ params: TemplateReplaceParams
+ ): CompletableFuture> =
+ replace(params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture>
}
}
diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsyncImpl.kt
index e16d2352..9b367d87 100644
--- a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsyncImpl.kt
+++ b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/TemplateServiceAsyncImpl.kt
@@ -13,12 +13,19 @@ import com.courier.core.http.HttpRequest
import com.courier.core.http.HttpResponse
import com.courier.core.http.HttpResponse.Handler
import com.courier.core.http.HttpResponseFor
+import com.courier.core.http.json
import com.courier.core.http.parseable
import com.courier.core.prepareAsync
import com.courier.models.tenants.BaseTemplateTenantAssociation
+import com.courier.models.tenants.PostTenantTemplatePublishResponse
+import com.courier.models.tenants.PutTenantTemplateResponse
import com.courier.models.tenants.templates.TemplateListParams
import com.courier.models.tenants.templates.TemplateListResponse
+import com.courier.models.tenants.templates.TemplatePublishParams
+import com.courier.models.tenants.templates.TemplateReplaceParams
import com.courier.models.tenants.templates.TemplateRetrieveParams
+import com.courier.services.async.tenants.templates.VersionServiceAsync
+import com.courier.services.async.tenants.templates.VersionServiceAsyncImpl
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import kotlin.jvm.optionals.getOrNull
@@ -30,11 +37,15 @@ class TemplateServiceAsyncImpl internal constructor(private val clientOptions: C
WithRawResponseImpl(clientOptions)
}
+ private val versions: VersionServiceAsync by lazy { VersionServiceAsyncImpl(clientOptions) }
+
override fun withRawResponse(): TemplateServiceAsync.WithRawResponse = withRawResponse
override fun withOptions(modifier: Consumer): TemplateServiceAsync =
TemplateServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build())
+ override fun versions(): VersionServiceAsync = versions
+
override fun retrieve(
params: TemplateRetrieveParams,
requestOptions: RequestOptions,
@@ -49,12 +60,30 @@ class TemplateServiceAsyncImpl internal constructor(private val clientOptions: C
// get /tenants/{tenant_id}/templates
withRawResponse().list(params, requestOptions).thenApply { it.parse() }
+ override fun publish(
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture =
+ // post /tenants/{tenant_id}/templates/{template_id}/publish
+ withRawResponse().publish(params, requestOptions).thenApply { it.parse() }
+
+ override fun replace(
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture =
+ // put /tenants/{tenant_id}/templates/{template_id}
+ withRawResponse().replace(params, requestOptions).thenApply { it.parse() }
+
class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
TemplateServiceAsync.WithRawResponse {
private val errorHandler: Handler =
errorHandler(errorBodyHandler(clientOptions.jsonMapper))
+ private val versions: VersionServiceAsync.WithRawResponse by lazy {
+ VersionServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
override fun withOptions(
modifier: Consumer
): TemplateServiceAsync.WithRawResponse =
@@ -62,6 +91,8 @@ class TemplateServiceAsyncImpl internal constructor(private val clientOptions: C
clientOptions.toBuilder().apply(modifier::accept).build()
)
+ override fun versions(): VersionServiceAsync.WithRawResponse = versions
+
private val retrieveHandler: Handler =
jsonHandler(clientOptions.jsonMapper)
@@ -132,5 +163,84 @@ class TemplateServiceAsyncImpl internal constructor(private val clientOptions: C
}
}
}
+
+ private val publishHandler: Handler =
+ jsonHandler(clientOptions.jsonMapper)
+
+ override fun publish(
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture> {
+ // We check here instead of in the params builder because this can be specified
+ // positionally or in the params class.
+ checkRequired("templateId", params.templateId().getOrNull())
+ val request =
+ HttpRequest.builder()
+ .method(HttpMethod.POST)
+ .baseUrl(clientOptions.baseUrl())
+ .addPathSegments(
+ "tenants",
+ params._pathParam(0),
+ "templates",
+ params._pathParam(1),
+ "publish",
+ )
+ .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } }
+ .build()
+ .prepareAsync(clientOptions, params)
+ val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions))
+ return request
+ .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) }
+ .thenApply { response ->
+ errorHandler.handle(response).parseable {
+ response
+ .use { publishHandler.handle(it) }
+ .also {
+ if (requestOptions.responseValidation!!) {
+ it.validate()
+ }
+ }
+ }
+ }
+ }
+
+ private val replaceHandler: Handler =
+ jsonHandler(clientOptions.jsonMapper)
+
+ override fun replace(
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture> {
+ // We check here instead of in the params builder because this can be specified
+ // positionally or in the params class.
+ checkRequired("templateId", params.templateId().getOrNull())
+ val request =
+ HttpRequest.builder()
+ .method(HttpMethod.PUT)
+ .baseUrl(clientOptions.baseUrl())
+ .addPathSegments(
+ "tenants",
+ params._pathParam(0),
+ "templates",
+ params._pathParam(1),
+ )
+ .body(json(clientOptions.jsonMapper, params._body()))
+ .build()
+ .prepareAsync(clientOptions, params)
+ val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions))
+ return request
+ .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) }
+ .thenApply { response ->
+ errorHandler.handle(response).parseable {
+ response
+ .use { replaceHandler.handle(it) }
+ .also {
+ if (requestOptions.responseValidation!!) {
+ it.validate()
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsync.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsync.kt
new file mode 100644
index 00000000..e03aed25
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsync.kt
@@ -0,0 +1,104 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.services.async.tenants.templates
+
+import com.courier.core.ClientOptions
+import com.courier.core.RequestOptions
+import com.courier.core.http.HttpResponseFor
+import com.courier.models.tenants.BaseTemplateTenantAssociation
+import com.courier.models.tenants.templates.versions.VersionRetrieveParams
+import java.util.concurrent.CompletableFuture
+import java.util.function.Consumer
+
+interface VersionServiceAsync {
+
+ /**
+ * Returns a view of this service that provides access to raw HTTP responses for each method.
+ */
+ fun withRawResponse(): WithRawResponse
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(modifier: Consumer): VersionServiceAsync
+
+ /**
+ * Fetches a specific version of a tenant template.
+ *
+ * Supports the following version formats:
+ * - `latest` - The most recent version of the template
+ * - `published` - The currently published version
+ * - `v{version}` - A specific version (e.g., "v1", "v2", "v1.0.0")
+ */
+ fun retrieve(
+ version: String,
+ params: VersionRetrieveParams,
+ ): CompletableFuture =
+ retrieve(version, params, RequestOptions.none())
+
+ /** @see retrieve */
+ fun retrieve(
+ version: String,
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture =
+ retrieve(params.toBuilder().version(version).build(), requestOptions)
+
+ /** @see retrieve */
+ fun retrieve(params: VersionRetrieveParams): CompletableFuture =
+ retrieve(params, RequestOptions.none())
+
+ /** @see retrieve */
+ fun retrieve(
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture
+
+ /**
+ * A view of [VersionServiceAsync] that provides access to raw HTTP responses for each method.
+ */
+ interface WithRawResponse {
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(
+ modifier: Consumer
+ ): VersionServiceAsync.WithRawResponse
+
+ /**
+ * Returns a raw HTTP response for `get
+ * /tenants/{tenant_id}/templates/{template_id}/versions/{version}`, but is otherwise the
+ * same as [VersionServiceAsync.retrieve].
+ */
+ fun retrieve(
+ version: String,
+ params: VersionRetrieveParams,
+ ): CompletableFuture> =
+ retrieve(version, params, RequestOptions.none())
+
+ /** @see retrieve */
+ fun retrieve(
+ version: String,
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture> =
+ retrieve(params.toBuilder().version(version).build(), requestOptions)
+
+ /** @see retrieve */
+ fun retrieve(
+ params: VersionRetrieveParams
+ ): CompletableFuture> =
+ retrieve(params, RequestOptions.none())
+
+ /** @see retrieve */
+ fun retrieve(
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): CompletableFuture>
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsyncImpl.kt
new file mode 100644
index 00000000..34666ba1
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/services/async/tenants/templates/VersionServiceAsyncImpl.kt
@@ -0,0 +1,96 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.services.async.tenants.templates
+
+import com.courier.core.ClientOptions
+import com.courier.core.RequestOptions
+import com.courier.core.checkRequired
+import com.courier.core.handlers.errorBodyHandler
+import com.courier.core.handlers.errorHandler
+import com.courier.core.handlers.jsonHandler
+import com.courier.core.http.HttpMethod
+import com.courier.core.http.HttpRequest
+import com.courier.core.http.HttpResponse
+import com.courier.core.http.HttpResponse.Handler
+import com.courier.core.http.HttpResponseFor
+import com.courier.core.http.parseable
+import com.courier.core.prepareAsync
+import com.courier.models.tenants.BaseTemplateTenantAssociation
+import com.courier.models.tenants.templates.versions.VersionRetrieveParams
+import java.util.concurrent.CompletableFuture
+import java.util.function.Consumer
+import kotlin.jvm.optionals.getOrNull
+
+class VersionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) :
+ VersionServiceAsync {
+
+ private val withRawResponse: VersionServiceAsync.WithRawResponse by lazy {
+ WithRawResponseImpl(clientOptions)
+ }
+
+ override fun withRawResponse(): VersionServiceAsync.WithRawResponse = withRawResponse
+
+ override fun withOptions(modifier: Consumer): VersionServiceAsync =
+ VersionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build())
+
+ override fun retrieve(
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture =
+ // get /tenants/{tenant_id}/templates/{template_id}/versions/{version}
+ withRawResponse().retrieve(params, requestOptions).thenApply { it.parse() }
+
+ class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
+ VersionServiceAsync.WithRawResponse {
+
+ private val errorHandler: Handler =
+ errorHandler(errorBodyHandler(clientOptions.jsonMapper))
+
+ override fun withOptions(
+ modifier: Consumer
+ ): VersionServiceAsync.WithRawResponse =
+ VersionServiceAsyncImpl.WithRawResponseImpl(
+ clientOptions.toBuilder().apply(modifier::accept).build()
+ )
+
+ private val retrieveHandler: Handler =
+ jsonHandler(clientOptions.jsonMapper)
+
+ override fun retrieve(
+ params: VersionRetrieveParams,
+ requestOptions: RequestOptions,
+ ): CompletableFuture> {
+ // We check here instead of in the params builder because this can be specified
+ // positionally or in the params class.
+ checkRequired("version", params.version().getOrNull())
+ val request =
+ HttpRequest.builder()
+ .method(HttpMethod.GET)
+ .baseUrl(clientOptions.baseUrl())
+ .addPathSegments(
+ "tenants",
+ params._pathParam(0),
+ "templates",
+ params._pathParam(1),
+ "versions",
+ params._pathParam(2),
+ )
+ .build()
+ .prepareAsync(clientOptions, params)
+ val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions))
+ return request
+ .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) }
+ .thenApply { response ->
+ errorHandler.handle(response).parseable {
+ response
+ .use { retrieveHandler.handle(it) }
+ .also {
+ if (requestOptions.responseValidation!!) {
+ it.validate()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/tenants/TemplateService.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/tenants/TemplateService.kt
index 5b21a915..77c3b221 100644
--- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/tenants/TemplateService.kt
+++ b/courier-java-core/src/main/kotlin/com/courier/services/blocking/tenants/TemplateService.kt
@@ -6,9 +6,14 @@ import com.courier.core.ClientOptions
import com.courier.core.RequestOptions
import com.courier.core.http.HttpResponseFor
import com.courier.models.tenants.BaseTemplateTenantAssociation
+import com.courier.models.tenants.PostTenantTemplatePublishResponse
+import com.courier.models.tenants.PutTenantTemplateResponse
import com.courier.models.tenants.templates.TemplateListParams
import com.courier.models.tenants.templates.TemplateListResponse
+import com.courier.models.tenants.templates.TemplatePublishParams
+import com.courier.models.tenants.templates.TemplateReplaceParams
import com.courier.models.tenants.templates.TemplateRetrieveParams
+import com.courier.services.blocking.tenants.templates.VersionService
import com.google.errorprone.annotations.MustBeClosed
import java.util.function.Consumer
@@ -26,6 +31,8 @@ interface TemplateService {
*/
fun withOptions(modifier: Consumer): TemplateService
+ fun versions(): VersionService
+
/** Get a Template in Tenant */
fun retrieve(
templateId: String,
@@ -79,6 +86,64 @@ interface TemplateService {
fun list(tenantId: String, requestOptions: RequestOptions): TemplateListResponse =
list(tenantId, TemplateListParams.none(), requestOptions)
+ /**
+ * Publishes a specific version of a notification template for a tenant.
+ *
+ * The template must already exist in the tenant's notification map. If no version is specified,
+ * defaults to publishing the "latest" version.
+ */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ ): PostTenantTemplatePublishResponse = publish(templateId, params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): PostTenantTemplatePublishResponse =
+ publish(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see publish */
+ fun publish(params: TemplatePublishParams): PostTenantTemplatePublishResponse =
+ publish(params, RequestOptions.none())
+
+ /** @see publish */
+ fun publish(
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): PostTenantTemplatePublishResponse
+
+ /**
+ * Creates or updates a notification template for a tenant.
+ *
+ * If the template already exists for the tenant, it will be updated (200). Otherwise, a new
+ * template is created (201).
+ *
+ * Optionally publishes the template immediately if the `published` flag is set to true.
+ */
+ fun replace(templateId: String, params: TemplateReplaceParams): PutTenantTemplateResponse =
+ replace(templateId, params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ templateId: String,
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): PutTenantTemplateResponse =
+ replace(params.toBuilder().templateId(templateId).build(), requestOptions)
+
+ /** @see replace */
+ fun replace(params: TemplateReplaceParams): PutTenantTemplateResponse =
+ replace(params, RequestOptions.none())
+
+ /** @see replace */
+ fun replace(
+ params: TemplateReplaceParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): PutTenantTemplateResponse
+
/** A view of [TemplateService] that provides access to raw HTTP responses for each method. */
interface WithRawResponse {
@@ -89,6 +154,8 @@ interface TemplateService {
*/
fun withOptions(modifier: Consumer): TemplateService.WithRawResponse
+ fun versions(): VersionService.WithRawResponse
+
/**
* Returns a raw HTTP response for `get /tenants/{tenant_id}/templates/{template_id}`, but
* is otherwise the same as [TemplateService.retrieve].
@@ -165,5 +232,72 @@ interface TemplateService {
requestOptions: RequestOptions,
): HttpResponseFor =
list(tenantId, TemplateListParams.none(), requestOptions)
+
+ /**
+ * Returns a raw HTTP response for `post
+ * /tenants/{tenant_id}/templates/{template_id}/publish`, but is otherwise the same as
+ * [TemplateService.publish].
+ */
+ @MustBeClosed
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ ): HttpResponseFor =
+ publish(templateId, params, RequestOptions.none())
+
+ /** @see publish */
+ @MustBeClosed
+ fun publish(
+ templateId: String,
+ params: TemplatePublishParams,
+ requestOptions: RequestOptions = RequestOptions.none(),
+ ): HttpResponseFor