Skip to content

Commit aee000e

Browse files
feat(api): add publish/replace methods and versions to tenant templates
1 parent b2f8e8d commit aee000e

File tree

7 files changed

+530
-5
lines changed

7 files changed

+530
-5
lines changed

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 78
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-2cde866450022e180983325c70421aa17a47ae9dbf6a7dbd935f3279d61a0172.yml
3-
openapi_spec_hash: d805377811f69d0b37c578ebf9d6bada
4-
config_hash: 93eb861d9572cea4d66edeab309e08c6
1+
configured_endpoints: 81
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-3fc1c86b4a83a16393aaf17d1fb3ac6098d30dd057ba872973b57285a7a3f0d0.yml
3+
openapi_spec_hash: 02a545d217b13399f311e99561f9de1d
4+
config_hash: 0789c3cddc625bb9712b3bded274ab6c

api.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,18 @@ Methods:
359359
Params Types:
360360

361361
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#DefaultPreferencesParam">DefaultPreferencesParam</a>
362+
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PostTenantTemplatePublishRequestParam">PostTenantTemplatePublishRequestParam</a>
363+
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PutTenantTemplateRequestParam">PutTenantTemplateRequestParam</a>
362364
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#SubscriptionTopicNewParam">SubscriptionTopicNewParam</a>
363365
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantAssociationParam">TenantAssociationParam</a>
366+
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateInputParam">TenantTemplateInputParam</a>
364367

365368
Response Types:
366369

367370
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#BaseTemplateTenantAssociation">BaseTemplateTenantAssociation</a>
368371
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#DefaultPreferences">DefaultPreferences</a>
372+
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PostTenantTemplatePublishResponse">PostTenantTemplatePublishResponse</a>
373+
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PutTenantTemplateResponse">PutTenantTemplateResponse</a>
369374
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#SubscriptionTopicNew">SubscriptionTopicNew</a>
370375
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#Tenant">Tenant</a>
371376
- <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantAssociation">TenantAssociation</a>
@@ -399,6 +404,14 @@ Methods:
399404

400405
- <code title="get /tenants/{tenant_id}/templates/{template_id}">client.Tenants.Templates.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, templateID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateGetParams">TenantTemplateGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#BaseTemplateTenantAssociation">BaseTemplateTenantAssociation</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
401406
- <code title="get /tenants/{tenant_id}/templates">client.Tenants.Templates.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, tenantID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateListParams">TenantTemplateListParams</a>) (\*<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateListResponse">TenantTemplateListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
407+
- <code title="post /tenants/{tenant_id}/templates/{template_id}/publish">client.Tenants.Templates.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateService.Publish">Publish</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, templateID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplatePublishParams">TenantTemplatePublishParams</a>) (\*<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PostTenantTemplatePublishResponse">PostTenantTemplatePublishResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
408+
- <code title="put /tenants/{tenant_id}/templates/{template_id}">client.Tenants.Templates.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateService.Replace">Replace</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, templateID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateReplaceParams">TenantTemplateReplaceParams</a>) (\*<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#PutTenantTemplateResponse">PutTenantTemplateResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
409+
410+
### Versions
411+
412+
Methods:
413+
414+
- <code title="get /tenants/{tenant_id}/templates/{template_id}/versions/{version}">client.Tenants.Templates.Versions.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateVersionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, version <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#TenantTemplateVersionGetParams">TenantTemplateVersionGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4">courier</a>.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#BaseTemplateTenantAssociation">BaseTemplateTenantAssociation</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
402415

403416
# Translations
404417

tenant.go

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,92 @@ func (r DefaultPreferencesItemParam) MarshalJSON() (data []byte, err error) {
199199
return param.MarshalObject(r, shadow{&r, false})
200200
}
201201

202+
// Request body for publishing a tenant template version
203+
type PostTenantTemplatePublishRequestParam struct {
204+
// The version of the template to publish (e.g., "v1", "v2", "latest"). If not
205+
// provided, defaults to "latest".
206+
Version param.Opt[string] `json:"version,omitzero"`
207+
paramObj
208+
}
209+
210+
func (r PostTenantTemplatePublishRequestParam) MarshalJSON() (data []byte, err error) {
211+
type shadow PostTenantTemplatePublishRequestParam
212+
return param.MarshalObject(r, (*shadow)(&r))
213+
}
214+
func (r *PostTenantTemplatePublishRequestParam) UnmarshalJSON(data []byte) error {
215+
return apijson.UnmarshalRoot(data, r)
216+
}
217+
218+
// Response from publishing a tenant template
219+
type PostTenantTemplatePublishResponse struct {
220+
// The template ID
221+
ID string `json:"id,required"`
222+
// The timestamp when the template was published
223+
PublishedAt string `json:"published_at,required"`
224+
// The published version of the template
225+
Version string `json:"version,required"`
226+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
227+
JSON struct {
228+
ID respjson.Field
229+
PublishedAt respjson.Field
230+
Version respjson.Field
231+
ExtraFields map[string]respjson.Field
232+
raw string
233+
} `json:"-"`
234+
}
235+
236+
// Returns the unmodified JSON received from the API
237+
func (r PostTenantTemplatePublishResponse) RawJSON() string { return r.JSON.raw }
238+
func (r *PostTenantTemplatePublishResponse) UnmarshalJSON(data []byte) error {
239+
return apijson.UnmarshalRoot(data, r)
240+
}
241+
242+
// Request body for creating or updating a tenant notification template
243+
//
244+
// The property Template is required.
245+
type PutTenantTemplateRequestParam struct {
246+
// Template configuration for creating or updating a tenant notification template
247+
Template TenantTemplateInputParam `json:"template,omitzero,required"`
248+
// Whether to publish the template immediately after saving. When true, the
249+
// template becomes the active/published version. When false (default), the
250+
// template is saved as a draft.
251+
Published param.Opt[bool] `json:"published,omitzero"`
252+
paramObj
253+
}
254+
255+
func (r PutTenantTemplateRequestParam) MarshalJSON() (data []byte, err error) {
256+
type shadow PutTenantTemplateRequestParam
257+
return param.MarshalObject(r, (*shadow)(&r))
258+
}
259+
func (r *PutTenantTemplateRequestParam) UnmarshalJSON(data []byte) error {
260+
return apijson.UnmarshalRoot(data, r)
261+
}
262+
263+
// Response from creating or updating a tenant notification template
264+
type PutTenantTemplateResponse struct {
265+
// The template ID
266+
ID string `json:"id,required"`
267+
// The version of the saved template
268+
Version string `json:"version,required"`
269+
// The timestamp when the template was published. Only present if the template was
270+
// published as part of this request.
271+
PublishedAt string `json:"published_at,nullable"`
272+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
273+
JSON struct {
274+
ID respjson.Field
275+
Version respjson.Field
276+
PublishedAt respjson.Field
277+
ExtraFields map[string]respjson.Field
278+
raw string
279+
} `json:"-"`
280+
}
281+
282+
// Returns the unmodified JSON received from the API
283+
func (r PutTenantTemplateResponse) RawJSON() string { return r.JSON.raw }
284+
func (r *PutTenantTemplateResponse) UnmarshalJSON(data []byte) error {
285+
return apijson.UnmarshalRoot(data, r)
286+
}
287+
202288
type SubscriptionTopicNew struct {
203289
// Any of "OPTED_OUT", "OPTED_IN", "REQUIRED".
204290
Status SubscriptionTopicNewStatus `json:"status,required"`
@@ -362,6 +448,120 @@ func (r *TenantAssociationParam) UnmarshalJSON(data []byte) error {
362448
return apijson.UnmarshalRoot(data, r)
363449
}
364450

451+
// Template configuration for creating or updating a tenant notification template
452+
//
453+
// The property Content is required.
454+
type TenantTemplateInputParam struct {
455+
// Template content configuration including blocks, elements, and message structure
456+
Content shared.ElementalContentParam `json:"content,omitzero,required"`
457+
// Channel-specific delivery configuration (email, SMS, push, etc.)
458+
Channels map[string]TenantTemplateInputChannelParam `json:"channels,omitzero"`
459+
// Provider-specific delivery configuration for routing to specific email/SMS
460+
// providers
461+
Providers map[string]TenantTemplateInputProviderParam `json:"providers,omitzero"`
462+
// Message routing configuration for multi-channel delivery strategies
463+
Routing shared.MessageRoutingParam `json:"routing,omitzero"`
464+
paramObj
465+
}
466+
467+
func (r TenantTemplateInputParam) MarshalJSON() (data []byte, err error) {
468+
type shadow TenantTemplateInputParam
469+
return param.MarshalObject(r, (*shadow)(&r))
470+
}
471+
func (r *TenantTemplateInputParam) UnmarshalJSON(data []byte) error {
472+
return apijson.UnmarshalRoot(data, r)
473+
}
474+
475+
type TenantTemplateInputChannelParam struct {
476+
// Brand id used for rendering.
477+
BrandID param.Opt[string] `json:"brand_id,omitzero"`
478+
// JS conditional with access to data/profile.
479+
If param.Opt[string] `json:"if,omitzero"`
480+
Metadata TenantTemplateInputChannelMetadataParam `json:"metadata,omitzero"`
481+
// Channel specific overrides.
482+
Override map[string]any `json:"override,omitzero"`
483+
// Providers enabled for this channel.
484+
Providers []string `json:"providers,omitzero"`
485+
// Defaults to `single`.
486+
//
487+
// Any of "all", "single".
488+
RoutingMethod string `json:"routing_method,omitzero"`
489+
Timeouts TenantTemplateInputChannelTimeoutsParam `json:"timeouts,omitzero"`
490+
paramObj
491+
}
492+
493+
func (r TenantTemplateInputChannelParam) MarshalJSON() (data []byte, err error) {
494+
type shadow TenantTemplateInputChannelParam
495+
return param.MarshalObject(r, (*shadow)(&r))
496+
}
497+
func (r *TenantTemplateInputChannelParam) UnmarshalJSON(data []byte) error {
498+
return apijson.UnmarshalRoot(data, r)
499+
}
500+
501+
func init() {
502+
apijson.RegisterFieldValidator[TenantTemplateInputChannelParam](
503+
"routing_method", "all", "single",
504+
)
505+
}
506+
507+
type TenantTemplateInputChannelMetadataParam struct {
508+
Utm shared.UtmParam `json:"utm,omitzero"`
509+
paramObj
510+
}
511+
512+
func (r TenantTemplateInputChannelMetadataParam) MarshalJSON() (data []byte, err error) {
513+
type shadow TenantTemplateInputChannelMetadataParam
514+
return param.MarshalObject(r, (*shadow)(&r))
515+
}
516+
func (r *TenantTemplateInputChannelMetadataParam) UnmarshalJSON(data []byte) error {
517+
return apijson.UnmarshalRoot(data, r)
518+
}
519+
520+
type TenantTemplateInputChannelTimeoutsParam struct {
521+
Channel param.Opt[int64] `json:"channel,omitzero"`
522+
Provider param.Opt[int64] `json:"provider,omitzero"`
523+
paramObj
524+
}
525+
526+
func (r TenantTemplateInputChannelTimeoutsParam) MarshalJSON() (data []byte, err error) {
527+
type shadow TenantTemplateInputChannelTimeoutsParam
528+
return param.MarshalObject(r, (*shadow)(&r))
529+
}
530+
func (r *TenantTemplateInputChannelTimeoutsParam) UnmarshalJSON(data []byte) error {
531+
return apijson.UnmarshalRoot(data, r)
532+
}
533+
534+
type TenantTemplateInputProviderParam struct {
535+
// JS conditional with access to data/profile.
536+
If param.Opt[string] `json:"if,omitzero"`
537+
Timeouts param.Opt[int64] `json:"timeouts,omitzero"`
538+
Metadata TenantTemplateInputProviderMetadataParam `json:"metadata,omitzero"`
539+
// Provider-specific overrides.
540+
Override map[string]any `json:"override,omitzero"`
541+
paramObj
542+
}
543+
544+
func (r TenantTemplateInputProviderParam) MarshalJSON() (data []byte, err error) {
545+
type shadow TenantTemplateInputProviderParam
546+
return param.MarshalObject(r, (*shadow)(&r))
547+
}
548+
func (r *TenantTemplateInputProviderParam) UnmarshalJSON(data []byte) error {
549+
return apijson.UnmarshalRoot(data, r)
550+
}
551+
552+
type TenantTemplateInputProviderMetadataParam struct {
553+
Utm shared.UtmParam `json:"utm,omitzero"`
554+
paramObj
555+
}
556+
557+
func (r TenantTemplateInputProviderMetadataParam) MarshalJSON() (data []byte, err error) {
558+
type shadow TenantTemplateInputProviderMetadataParam
559+
return param.MarshalObject(r, (*shadow)(&r))
560+
}
561+
func (r *TenantTemplateInputProviderMetadataParam) UnmarshalJSON(data []byte) error {
562+
return apijson.UnmarshalRoot(data, r)
563+
}
564+
365565
type TenantListResponse struct {
366566
// Set to true when there are more pages that can be retrieved.
367567
HasMore bool `json:"has_more,required"`

tenanttemplate.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package courier
44

55
import (
66
"context"
7+
"encoding/json"
78
"errors"
89
"fmt"
910
"net/http"
@@ -12,6 +13,7 @@ import (
1213

1314
"github.com/trycourier/courier-go/v4/internal/apijson"
1415
"github.com/trycourier/courier-go/v4/internal/apiquery"
16+
shimjson "github.com/trycourier/courier-go/v4/internal/encoding/json"
1517
"github.com/trycourier/courier-go/v4/internal/requestconfig"
1618
"github.com/trycourier/courier-go/v4/option"
1719
"github.com/trycourier/courier-go/v4/packages/param"
@@ -26,7 +28,8 @@ import (
2628
// automatically. You should not instantiate this service directly, and instead use
2729
// the [NewTenantTemplateService] method instead.
2830
type TenantTemplateService struct {
29-
Options []option.RequestOption
31+
Options []option.RequestOption
32+
Versions TenantTemplateVersionService
3033
}
3134

3235
// NewTenantTemplateService generates a new service that applies the given options
@@ -35,6 +38,7 @@ type TenantTemplateService struct {
3538
func NewTenantTemplateService(opts ...option.RequestOption) (r TenantTemplateService) {
3639
r = TenantTemplateService{}
3740
r.Options = opts
41+
r.Versions = NewTenantTemplateVersionService(opts...)
3842
return
3943
}
4044

@@ -66,6 +70,47 @@ func (r *TenantTemplateService) List(ctx context.Context, tenantID string, query
6670
return
6771
}
6872

73+
// Publishes a specific version of a notification template for a tenant.
74+
//
75+
// The template must already exist in the tenant's notification map. If no version
76+
// is specified, defaults to publishing the "latest" version.
77+
func (r *TenantTemplateService) Publish(ctx context.Context, templateID string, params TenantTemplatePublishParams, opts ...option.RequestOption) (res *PostTenantTemplatePublishResponse, err error) {
78+
opts = slices.Concat(r.Options, opts)
79+
if params.TenantID == "" {
80+
err = errors.New("missing required tenant_id parameter")
81+
return
82+
}
83+
if templateID == "" {
84+
err = errors.New("missing required template_id parameter")
85+
return
86+
}
87+
path := fmt.Sprintf("tenants/%s/templates/%s/publish", params.TenantID, templateID)
88+
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
89+
return
90+
}
91+
92+
// Creates or updates a notification template for a tenant.
93+
//
94+
// If the template already exists for the tenant, it will be updated (200).
95+
// Otherwise, a new template is created (201).
96+
//
97+
// Optionally publishes the template immediately if the `published` flag is set to
98+
// true.
99+
func (r *TenantTemplateService) Replace(ctx context.Context, templateID string, params TenantTemplateReplaceParams, opts ...option.RequestOption) (res *PutTenantTemplateResponse, err error) {
100+
opts = slices.Concat(r.Options, opts)
101+
if params.TenantID == "" {
102+
err = errors.New("missing required tenant_id parameter")
103+
return
104+
}
105+
if templateID == "" {
106+
err = errors.New("missing required template_id parameter")
107+
return
108+
}
109+
path := fmt.Sprintf("tenants/%s/templates/%s", params.TenantID, templateID)
110+
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &res, opts...)
111+
return
112+
}
113+
69114
type TenantTemplateListResponse struct {
70115
// Set to true when there are more pages that can be retrieved.
71116
HasMore bool `json:"has_more,required"`
@@ -164,3 +209,31 @@ func (r TenantTemplateListParams) URLQuery() (v url.Values, err error) {
164209
NestedFormat: apiquery.NestedQueryFormatBrackets,
165210
})
166211
}
212+
213+
type TenantTemplatePublishParams struct {
214+
TenantID string `path:"tenant_id,required" json:"-"`
215+
// Request body for publishing a tenant template version
216+
PostTenantTemplatePublishRequest PostTenantTemplatePublishRequestParam
217+
paramObj
218+
}
219+
220+
func (r TenantTemplatePublishParams) MarshalJSON() (data []byte, err error) {
221+
return shimjson.Marshal(r.PostTenantTemplatePublishRequest)
222+
}
223+
func (r *TenantTemplatePublishParams) UnmarshalJSON(data []byte) error {
224+
return json.Unmarshal(data, &r.PostTenantTemplatePublishRequest)
225+
}
226+
227+
type TenantTemplateReplaceParams struct {
228+
TenantID string `path:"tenant_id,required" json:"-"`
229+
// Request body for creating or updating a tenant notification template
230+
PutTenantTemplateRequest PutTenantTemplateRequestParam
231+
paramObj
232+
}
233+
234+
func (r TenantTemplateReplaceParams) MarshalJSON() (data []byte, err error) {
235+
return shimjson.Marshal(r.PutTenantTemplateRequest)
236+
}
237+
func (r *TenantTemplateReplaceParams) UnmarshalJSON(data []byte) error {
238+
return json.Unmarshal(data, &r.PutTenantTemplateRequest)
239+
}

0 commit comments

Comments
 (0)