Skip to content

Commit 27e1dcc

Browse files
feat(api): add list/invoke methods to journeys
1 parent 85aeba9 commit 27e1dcc

File tree

5 files changed

+314
-4
lines changed

5 files changed

+314
-4
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: 81
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-44c2e612f5d40e03f56712a4e123a193e6ea03cc64a91d0c34ee094563dafa1c.yml
3-
openapi_spec_hash: 40bf6b3f7992d55f1bd543f32564ea86
4-
config_hash: b1f6d0f43161b66d201043fcbe5c5695
1+
configured_endpoints: 83
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-af83ac9631c6a9f5651adda37ef80ba220f4b54b80f029ab8f04a0bb165af6c2.yml
3+
openapi_spec_hash: a1d2bf40aec49ea35bcef11de0349e45
4+
config_hash: c1bd72f347662bde65ed9abec4c33b13

api.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,23 @@ Methods:
149149
- <code title="post /automations/invoke">client.Automations.Invoke.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#AutomationInvokeService.InvokeAdHoc">InvokeAdHoc</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <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#AutomationInvokeInvokeAdHocParams">AutomationInvokeInvokeAdHocParams</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#AutomationInvokeResponse">AutomationInvokeResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
150150
- <code title="post /automations/{templateId}/invoke">client.Automations.Invoke.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#AutomationInvokeService.InvokeByTemplate">InvokeByTemplate</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>, body <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#AutomationInvokeInvokeByTemplateParams">AutomationInvokeInvokeByTemplateParams</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#AutomationInvokeResponse">AutomationInvokeResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
151151

152+
# Journeys
153+
154+
Params Types:
155+
156+
- <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#JourneysInvokeRequestParam">JourneysInvokeRequestParam</a>
157+
158+
Response Types:
159+
160+
- <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#Journey">Journey</a>
161+
- <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#JourneysInvokeResponse">JourneysInvokeResponse</a>
162+
- <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#JourneysListResponse">JourneysListResponse</a>
163+
164+
Methods:
165+
166+
- <code title="get /journeys">client.Journeys.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#JourneyService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</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#JourneyListParams">JourneyListParams</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#JourneysListResponse">JourneysListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
167+
- <code title="post /journeys/{templateId}/invoke">client.Journeys.<a href="https://pkg.go.dev/github.com/trycourier/courier-go/v4#JourneyService.Invoke">Invoke</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>, body <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#JourneyInvokeParams">JourneyInvokeParams</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#JourneysInvokeResponse">JourneysInvokeResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
168+
152169
# Brands
153170

154171
Params Types:

client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type Client struct {
2222
AuditEvents AuditEventService
2323
Auth AuthService
2424
Automations AutomationService
25+
Journeys JourneyService
2526
Brands BrandService
2627
Bulk BulkService
2728
Inbound InboundService
@@ -62,6 +63,7 @@ func NewClient(opts ...option.RequestOption) (r Client) {
6263
r.AuditEvents = NewAuditEventService(opts...)
6364
r.Auth = NewAuthService(opts...)
6465
r.Automations = NewAutomationService(opts...)
66+
r.Journeys = NewJourneyService(opts...)
6567
r.Brands = NewBrandService(opts...)
6668
r.Bulk = NewBulkService(opts...)
6769
r.Inbound = NewInboundService(opts...)

journey.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
package courier
4+
5+
import (
6+
"context"
7+
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"net/http"
11+
"net/url"
12+
"slices"
13+
"time"
14+
15+
"github.com/trycourier/courier-go/v4/internal/apijson"
16+
"github.com/trycourier/courier-go/v4/internal/apiquery"
17+
shimjson "github.com/trycourier/courier-go/v4/internal/encoding/json"
18+
"github.com/trycourier/courier-go/v4/internal/requestconfig"
19+
"github.com/trycourier/courier-go/v4/option"
20+
"github.com/trycourier/courier-go/v4/packages/param"
21+
"github.com/trycourier/courier-go/v4/packages/respjson"
22+
)
23+
24+
// JourneyService contains methods and other services that help with interacting
25+
// with the Courier API.
26+
//
27+
// Note, unlike clients, this service does not read variables from the environment
28+
// automatically. You should not instantiate this service directly, and instead use
29+
// the [NewJourneyService] method instead.
30+
type JourneyService struct {
31+
Options []option.RequestOption
32+
}
33+
34+
// NewJourneyService generates a new service that applies the given options to each
35+
// request. These options are applied after the parent client's options (if there
36+
// is one), and before any request-specific options.
37+
func NewJourneyService(opts ...option.RequestOption) (r JourneyService) {
38+
r = JourneyService{}
39+
r.Options = opts
40+
return
41+
}
42+
43+
// Get the list of journeys.
44+
func (r *JourneyService) List(ctx context.Context, query JourneyListParams, opts ...option.RequestOption) (res *JourneysListResponse, err error) {
45+
opts = slices.Concat(r.Options, opts)
46+
path := "journeys"
47+
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
48+
return res, err
49+
}
50+
51+
// Invoke a journey run from a journey template.
52+
func (r *JourneyService) Invoke(ctx context.Context, templateID string, body JourneyInvokeParams, opts ...option.RequestOption) (res *JourneysInvokeResponse, err error) {
53+
opts = slices.Concat(r.Options, opts)
54+
if templateID == "" {
55+
err = errors.New("missing required templateId parameter")
56+
return nil, err
57+
}
58+
path := fmt.Sprintf("journeys/%s/invoke", templateID)
59+
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
60+
return res, err
61+
}
62+
63+
// A journey template representing an automation workflow.
64+
type Journey struct {
65+
// The unique identifier of the journey.
66+
ID string `json:"id" api:"required"`
67+
// The name of the journey.
68+
Name string `json:"name" api:"required"`
69+
// The version of the journey (published or draft).
70+
//
71+
// Any of "published", "draft".
72+
Version JourneyVersion `json:"version" api:"required"`
73+
// ISO 8601 timestamp when the journey was created.
74+
CreatedAt time.Time `json:"createdAt" format:"date-time"`
75+
// ISO 8601 timestamp when the journey was last updated.
76+
UpdatedAt time.Time `json:"updatedAt" format:"date-time"`
77+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
78+
JSON struct {
79+
ID respjson.Field
80+
Name respjson.Field
81+
Version respjson.Field
82+
CreatedAt respjson.Field
83+
UpdatedAt respjson.Field
84+
ExtraFields map[string]respjson.Field
85+
raw string
86+
} `json:"-"`
87+
}
88+
89+
// Returns the unmodified JSON received from the API
90+
func (r Journey) RawJSON() string { return r.JSON.raw }
91+
func (r *Journey) UnmarshalJSON(data []byte) error {
92+
return apijson.UnmarshalRoot(data, r)
93+
}
94+
95+
// The version of the journey (published or draft).
96+
type JourneyVersion string
97+
98+
const (
99+
JourneyVersionPublished JourneyVersion = "published"
100+
JourneyVersionDraft JourneyVersion = "draft"
101+
)
102+
103+
// Request body for invoking a journey. Requires either a user identifier or a
104+
// profile with contact information. User identifiers can be provided via user_id
105+
// field, or resolved from profile/data objects (user_id, userId, or anonymousId
106+
// fields).
107+
type JourneysInvokeRequestParam struct {
108+
// A unique identifier for the user. If not provided, the system will attempt to
109+
// resolve the user identifier from profile or data objects.
110+
UserID param.Opt[string] `json:"user_id,omitzero"`
111+
// Data payload passed to the journey. The expected shape can be predefined using
112+
// the schema builder in the journey editor. This data is available in journey
113+
// steps for condition evaluation and template variable interpolation. Can also
114+
// contain user identifiers (user_id, userId, anonymousId) if not provided
115+
// elsewhere.
116+
Data map[string]any `json:"data,omitzero"`
117+
// Profile data for the user. Can contain contact information (email,
118+
// phone_number), user identifiers (user_id, userId, anonymousId), or any custom
119+
// profile fields. Profile fields are merged with any existing stored profile for
120+
// the user. Include context.tenant_id to load a tenant-scoped profile for
121+
// multi-tenant scenarios.
122+
Profile map[string]any `json:"profile,omitzero"`
123+
paramObj
124+
}
125+
126+
func (r JourneysInvokeRequestParam) MarshalJSON() (data []byte, err error) {
127+
type shadow JourneysInvokeRequestParam
128+
return param.MarshalObject(r, (*shadow)(&r))
129+
}
130+
func (r *JourneysInvokeRequestParam) UnmarshalJSON(data []byte) error {
131+
return apijson.UnmarshalRoot(data, r)
132+
}
133+
134+
type JourneysInvokeResponse struct {
135+
// A unique identifier for the journey run that was created.
136+
RunID string `json:"runId" api:"required"`
137+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
138+
JSON struct {
139+
RunID respjson.Field
140+
ExtraFields map[string]respjson.Field
141+
raw string
142+
} `json:"-"`
143+
}
144+
145+
// Returns the unmodified JSON received from the API
146+
func (r JourneysInvokeResponse) RawJSON() string { return r.JSON.raw }
147+
func (r *JourneysInvokeResponse) UnmarshalJSON(data []byte) error {
148+
return apijson.UnmarshalRoot(data, r)
149+
}
150+
151+
type JourneysListResponse struct {
152+
// A cursor token for pagination. Present when there are more results available.
153+
Cursor string `json:"cursor"`
154+
Templates []Journey `json:"templates"`
155+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
156+
JSON struct {
157+
Cursor respjson.Field
158+
Templates respjson.Field
159+
ExtraFields map[string]respjson.Field
160+
raw string
161+
} `json:"-"`
162+
}
163+
164+
// Returns the unmodified JSON received from the API
165+
func (r JourneysListResponse) RawJSON() string { return r.JSON.raw }
166+
func (r *JourneysListResponse) UnmarshalJSON(data []byte) error {
167+
return apijson.UnmarshalRoot(data, r)
168+
}
169+
170+
type JourneyListParams struct {
171+
// A cursor token for pagination. Use the cursor from the previous response to
172+
// fetch the next page of results.
173+
Cursor param.Opt[string] `query:"cursor,omitzero" json:"-"`
174+
// The version of journeys to retrieve. Accepted values are published (for
175+
// published journeys) or draft (for draft journeys). Defaults to published.
176+
//
177+
// Any of "published", "draft".
178+
Version JourneyListParamsVersion `query:"version,omitzero" json:"-"`
179+
paramObj
180+
}
181+
182+
// URLQuery serializes [JourneyListParams]'s query parameters as `url.Values`.
183+
func (r JourneyListParams) URLQuery() (v url.Values, err error) {
184+
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
185+
ArrayFormat: apiquery.ArrayQueryFormatComma,
186+
NestedFormat: apiquery.NestedQueryFormatBrackets,
187+
})
188+
}
189+
190+
// The version of journeys to retrieve. Accepted values are published (for
191+
// published journeys) or draft (for draft journeys). Defaults to published.
192+
type JourneyListParamsVersion string
193+
194+
const (
195+
JourneyListParamsVersionPublished JourneyListParamsVersion = "published"
196+
JourneyListParamsVersionDraft JourneyListParamsVersion = "draft"
197+
)
198+
199+
type JourneyInvokeParams struct {
200+
// Request body for invoking a journey. Requires either a user identifier or a
201+
// profile with contact information. User identifiers can be provided via user_id
202+
// field, or resolved from profile/data objects (user_id, userId, or anonymousId
203+
// fields).
204+
JourneysInvokeRequest JourneysInvokeRequestParam
205+
paramObj
206+
}
207+
208+
func (r JourneyInvokeParams) MarshalJSON() (data []byte, err error) {
209+
return shimjson.Marshal(r.JourneysInvokeRequest)
210+
}
211+
func (r *JourneyInvokeParams) UnmarshalJSON(data []byte) error {
212+
return json.Unmarshal(data, &r.JourneysInvokeRequest)
213+
}

journey_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
package courier_test
4+
5+
import (
6+
"context"
7+
"errors"
8+
"os"
9+
"testing"
10+
11+
"github.com/trycourier/courier-go/v4"
12+
"github.com/trycourier/courier-go/v4/internal/testutil"
13+
"github.com/trycourier/courier-go/v4/option"
14+
)
15+
16+
func TestJourneyListWithOptionalParams(t *testing.T) {
17+
t.Skip("Mock server tests are disabled")
18+
baseURL := "http://localhost:4010"
19+
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
20+
baseURL = envURL
21+
}
22+
if !testutil.CheckTestServer(t, baseURL) {
23+
return
24+
}
25+
client := courier.NewClient(
26+
option.WithBaseURL(baseURL),
27+
option.WithAPIKey("My API Key"),
28+
)
29+
_, err := client.Journeys.List(context.TODO(), courier.JourneyListParams{
30+
Cursor: courier.String("cursor"),
31+
Version: courier.JourneyListParamsVersionPublished,
32+
})
33+
if err != nil {
34+
var apierr *courier.Error
35+
if errors.As(err, &apierr) {
36+
t.Log(string(apierr.DumpRequest(true)))
37+
}
38+
t.Fatalf("err should be nil: %s", err.Error())
39+
}
40+
}
41+
42+
func TestJourneyInvokeWithOptionalParams(t *testing.T) {
43+
t.Skip("Mock server tests are disabled")
44+
baseURL := "http://localhost:4010"
45+
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
46+
baseURL = envURL
47+
}
48+
if !testutil.CheckTestServer(t, baseURL) {
49+
return
50+
}
51+
client := courier.NewClient(
52+
option.WithBaseURL(baseURL),
53+
option.WithAPIKey("My API Key"),
54+
)
55+
_, err := client.Journeys.Invoke(
56+
context.TODO(),
57+
"templateId",
58+
courier.JourneyInvokeParams{
59+
JourneysInvokeRequest: courier.JourneysInvokeRequestParam{
60+
Data: map[string]any{
61+
"order_id": "bar",
62+
"amount": "bar",
63+
},
64+
Profile: map[string]any{
65+
"foo": "bar",
66+
},
67+
UserID: courier.String("user-123"),
68+
},
69+
},
70+
)
71+
if err != nil {
72+
var apierr *courier.Error
73+
if errors.As(err, &apierr) {
74+
t.Log(string(apierr.DumpRequest(true)))
75+
}
76+
t.Fatalf("err should be nil: %s", err.Error())
77+
}
78+
}

0 commit comments

Comments
 (0)