diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index aa6f6adf..83a317ac 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,10 +21,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/courier-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
@@ -43,10 +43,10 @@ jobs:
contents: read
id-token: write
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
@@ -61,7 +61,7 @@ jobs:
github.repository == 'stainless-sdks/courier-typescript' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
- uses: actions/github-script@v8
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());
@@ -80,10 +80,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/courier-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml
index 0bd63d73..d4cee411 100644
--- a/.github/workflows/publish-npm.yml
+++ b/.github/workflows/publish-npm.yml
@@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
with:
node-version: '20'
diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml
index 8fe0b398..ad46a4bd 100644
--- a/.github/workflows/release-doctor.yml
+++ b/.github/workflows/release-doctor.yml
@@ -12,11 +12,10 @@ jobs:
if: github.repository == 'trycourier/courier-node' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check release environment
run: |
bash ./bin/check-release-environment
env:
NPM_TOKEN: ${{ secrets.COURIER_NPM_TOKEN || secrets.NPM_TOKEN }}
-
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 1c3fc076..1421b84e 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "7.10.2"
+ ".": "7.11.0"
}
diff --git a/.stats.yml b/.stats.yml
index effa635e..d43ae964 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 103
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-3f78581b4e078a1f620d9f587f18d77bcde6d20f56b0e4ae798648f4236494fb.yml
-openapi_spec_hash: 6bd33e0396d85e11bb46f0d549af93a3
-config_hash: afcc4f6f8c33ca3f338589e32e086f56
+configured_endpoints: 117
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-ebe0d758a32897eaf20f252329168bbe2c2da7f580bb871357e63f4b451c684e.yml
+openapi_spec_hash: ba0c3cf85aa82f17744e217258a55b2e
+config_hash: 10bd597dd6cc89023541bc551b6532b8
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a61ec82d..2f7353b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## 7.11.0 (2026-05-15)
+
+Full Changelog: [v7.10.2...v7.11.0](https://github.com/trycourier/courier-node/compare/v7.10.2...v7.11.0)
+
+### Features
+
+* [SUP-607] Add DELETE endpoint for Courier Create tenant templates ([c5769b4](https://github.com/trycourier/courier-node/commit/c5769b4bfd047d0b3914f35403a2a6bac9a207c4))
+* **api:** add journeys CRUD/publish/versioning, templates sub-resource, types ([297d6eb](https://github.com/trycourier/courier-node/commit/297d6eb106b494cb56f3722a124a096736f1f83a))
+* support setting headers via env ([e7a078f](https://github.com/trycourier/courier-node/commit/e7a078f8e44790bf9332c5c06891d3fa9b148ee7))
+
+
+### Chores
+
+* **format:** run eslint and prettier separately ([94cc158](https://github.com/trycourier/courier-node/commit/94cc1583b4dcfe832929c142efaf5bf8b371b42f))
+* **formatter:** run prettier and eslint separately ([ee1ac34](https://github.com/trycourier/courier-node/commit/ee1ac34270e0607eb8f6f6ea884b37a7c9167e3d))
+* **internal:** codegen related update ([6197029](https://github.com/trycourier/courier-node/commit/619702960b9076a75bc7138a5218d06f4b3c5dc3))
+* **internal:** more robust bootstrap script ([1625ecf](https://github.com/trycourier/courier-node/commit/1625ecf85ab5a9550217acb1b6655c9ea5611fa3))
+* redact api-key headers in debug logs ([ce91d48](https://github.com/trycourier/courier-node/commit/ce91d48d8a4be2500a03433a03bafd8142d78e08))
+
## 7.10.2 (2026-04-14)
Full Changelog: [v7.10.1...v7.10.2](https://github.com/trycourier/courier-node/compare/v7.10.1...v7.10.2)
diff --git a/api.md b/api.md
index 3d9ffa24..d25051f7 100644
--- a/api.md
+++ b/api.md
@@ -178,15 +178,62 @@ Methods:
Types:
-- Journey
-- JourneysInvokeRequest
-- JourneysInvokeResponse
-- JourneysListResponse
+- CreateJourneyRequest
+- Journey
+- JourneyAINode
+- JourneyAPIInvokeTriggerNode
+- JourneyConditionAtom
+- JourneyConditionGroup
+- JourneyConditionNestedGroup
+- JourneyConditionsField
+- JourneyDelayDurationNode
+- JourneyDelayUntilNode
+- JourneyExitNode
+- JourneyFetchGetDeleteNode
+- JourneyFetchPostPutNode
+- JourneyMergeStrategy
+- JourneyNode
+- JourneyPublishRequest
+- JourneyResponse
+- JourneySegmentTriggerNode
+- JourneySendNode
+- JourneyState
+- JourneyTemplateCreateRequest
+- JourneyTemplateGetResponse
+- JourneyTemplateListResponse
+- JourneyTemplatePublishRequest
+- JourneyTemplateReplaceRequest
+- JourneyTemplateSummary
+- JourneyThrottleDynamicNode
+- JourneyThrottleStaticNode
+- JourneyVersionItem
+- JourneyVersionsListResponse
+- JourneysInvokeRequest
+- JourneysInvokeResponse
+- JourneysListResponse
Methods:
-- client.journeys.list({ ...params }) -> JourneysListResponse
-- client.journeys.invoke(templateID, { ...params }) -> JourneysInvokeResponse
+- client.journeys.create({ ...params }) -> JourneyResponse
+- client.journeys.retrieve(templateID, { ...params }) -> JourneyResponse
+- client.journeys.list({ ...params }) -> JourneysListResponse
+- client.journeys.archive(templateID) -> void
+- client.journeys.invoke(templateID, { ...params }) -> JourneysInvokeResponse
+- client.journeys.listVersions(templateID) -> JourneyVersionsListResponse
+- client.journeys.publish(templateID, { ...params }) -> JourneyResponse
+- client.journeys.replace(templateID, { ...params }) -> JourneyResponse
+
+## Templates
+
+Methods:
+
+- client.journeys.templates.create(templateID, { ...params }) -> JourneyTemplateGetResponse
+- client.journeys.templates.retrieve(notificationID, { ...params }) -> JourneyTemplateGetResponse
+- client.journeys.templates.list(templateID, { ...params }) -> JourneyTemplateListResponse
+- client.journeys.templates.archive(notificationID, { ...params }) -> void
+- client.journeys.templates.listVersions(notificationID, { ...params }) -> NotificationTemplateVersionListResponse
+- client.journeys.templates.publish(notificationID, { ...params }) -> void
+- client.journeys.templates.replace(notificationID, { ...params }) -> JourneyTemplateGetResponse
# Brands
@@ -445,6 +492,7 @@ Methods:
- client.tenants.templates.retrieve(templateID, { ...params }) -> BaseTemplateTenantAssociation
- client.tenants.templates.list(tenantID, { ...params }) -> TemplateListResponse
+- client.tenants.templates.delete(templateID, { ...params }) -> void
- client.tenants.templates.publish(templateID, { ...params }) -> PostTenantTemplatePublishResponse
- client.tenants.templates.replace(templateID, { ...params }) -> PutTenantTemplateResponse
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 7850bf49..07b28b78 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,7 +1,6 @@
// @ts-check
import tseslint from 'typescript-eslint';
import unusedImports from 'eslint-plugin-unused-imports';
-import prettier from 'eslint-plugin-prettier';
export default tseslint.config(
{
@@ -14,11 +13,9 @@ export default tseslint.config(
plugins: {
'@typescript-eslint': tseslint.plugin,
'unused-imports': unusedImports,
- prettier,
},
rules: {
'no-unused-vars': 'off',
- 'prettier/prettier': 'error',
'unused-imports/no-unused-imports': 'error',
'no-restricted-imports': [
'error',
diff --git a/package.json b/package.json
index 8aeaadf7..d26d2840 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@trycourier/courier",
- "version": "7.10.2",
+ "version": "7.11.0",
"description": "The official TypeScript library for the Courier API",
"author": "Courier ",
"types": "dist/index.d.ts",
@@ -36,7 +36,6 @@
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
"eslint": "^9.39.1",
- "eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-unused-imports": "^4.1.4",
"iconv-lite": "^0.6.3",
"jest": "^29.4.0",
diff --git a/scripts/bootstrap b/scripts/bootstrap
index a8b69ff3..2e315f53 100755
--- a/scripts/bootstrap
+++ b/scripts/bootstrap
@@ -4,7 +4,7 @@ set -e
cd "$(dirname "$0")/.."
-if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then
+if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then
brew bundle check >/dev/null 2>&1 || {
echo -n "==> Install Homebrew dependencies? (y/N): "
read -r response
diff --git a/scripts/fast-format b/scripts/fast-format
index 53721ac0..f1873aef 100755
--- a/scripts/fast-format
+++ b/scripts/fast-format
@@ -31,10 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then
fi
echo "==> Running prettier --write"
-# format things eslint didn't
-PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)"
-if ! [ -z "$PRETTIER_FILES" ]; then
- echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \
- --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \
- '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs'
+if ! [ -z "$FILE_LIST" ]; then
+ cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \
+ --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown
fi
diff --git a/scripts/format b/scripts/format
index 7a756401..b1b2c17a 100755
--- a/scripts/format
+++ b/scripts/format
@@ -8,5 +8,4 @@ echo "==> Running eslint --fix"
./node_modules/.bin/eslint --fix .
echo "==> Running prettier --write"
-# format things eslint didn't
-./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs'
+./node_modules/.bin/prettier --write --cache --cache-strategy metadata .
diff --git a/scripts/lint b/scripts/lint
index 3ffb78a6..1f532548 100755
--- a/scripts/lint
+++ b/scripts/lint
@@ -4,6 +4,9 @@ set -e
cd "$(dirname "$0")/.."
+echo "==> Running prettier --check"
+./node_modules/.bin/prettier --check .
+
echo "==> Running eslint"
./node_modules/.bin/eslint .
diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs
index deae575e..a8cdeb7c 100644
--- a/scripts/utils/postprocess-files.cjs
+++ b/scripts/utils/postprocess-files.cjs
@@ -23,12 +23,19 @@ async function postprocess() {
// strip out lib="dom", types="node", and types="react" references; these
// are needed at build time, but would pollute the user's TS environment
- const transformed = code.replace(
+ let transformed = code.replace(
/^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n',
);
+ // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same
+ // line as the type declaration, which doesn't work. So we convert to // @ts-ignore
+ // on its own line to properly suppresses errors.
+ if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) {
+ transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n');
+ }
+
if (transformed !== code) {
console.error(`wrote ${path.relative(process.cwd(), file)}`);
await fs.promises.writeFile(file, transformed, 'utf8');
diff --git a/src/client.ts b/src/client.ts
index a55a0521..87734246 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -67,15 +67,6 @@ import {
InboundBulkMessageUser,
} from './resources/bulk';
import { Inbound, InboundTrackEventParams, InboundTrackEventResponse } from './resources/inbound';
-import {
- Journey,
- JourneyInvokeParams,
- JourneyListParams,
- Journeys,
- JourneysInvokeRequest,
- JourneysInvokeResponse,
- JourneysListResponse,
-} from './resources/journeys';
import {
MessageContentResponse,
MessageDetails,
@@ -114,6 +105,48 @@ import {
AutomationTemplateListResponse,
Automations,
} from './resources/automations/automations';
+import {
+ CreateJourneyRequest,
+ Journey,
+ JourneyAINode,
+ JourneyAPIInvokeTriggerNode,
+ JourneyConditionAtom,
+ JourneyConditionGroup,
+ JourneyConditionNestedGroup,
+ JourneyConditionsField,
+ JourneyCreateParams,
+ JourneyDelayDurationNode,
+ JourneyDelayUntilNode,
+ JourneyExitNode,
+ JourneyFetchGetDeleteNode,
+ JourneyFetchPostPutNode,
+ JourneyInvokeParams,
+ JourneyListParams,
+ JourneyMergeStrategy,
+ JourneyNode,
+ JourneyPublishParams,
+ JourneyPublishRequest,
+ JourneyReplaceParams,
+ JourneyResponse,
+ JourneyRetrieveParams,
+ JourneySegmentTriggerNode,
+ JourneySendNode,
+ JourneyState,
+ JourneyTemplateCreateRequest,
+ JourneyTemplateGetResponse,
+ JourneyTemplateListResponse,
+ JourneyTemplatePublishRequest,
+ JourneyTemplateReplaceRequest,
+ JourneyTemplateSummary,
+ JourneyThrottleDynamicNode,
+ JourneyThrottleStaticNode,
+ JourneyVersionItem,
+ JourneyVersionsListResponse,
+ Journeys,
+ JourneysInvokeRequest,
+ JourneysInvokeResponse,
+ JourneysListResponse,
+} from './resources/journeys/journeys';
import {
ListListParams,
ListListResponse,
@@ -344,6 +377,18 @@ export class Courier {
this.fetch = options.fetch ?? Shims.getDefaultFetch();
this.#encoder = Opts.FallbackEncoder;
+ const customHeadersEnv = readEnv('COURIER_CUSTOM_HEADERS');
+ if (customHeadersEnv) {
+ const parsed: Record = {};
+ for (const line of customHeadersEnv.split('\n')) {
+ const colon = line.indexOf(':');
+ if (colon >= 0) {
+ parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim();
+ }
+ }
+ options.defaultHeaders = { ...parsed, ...options.defaultHeaders };
+ }
+
this._options = options;
this.apiKey = apiKey;
@@ -985,12 +1030,45 @@ export declare namespace Courier {
export {
Journeys as Journeys,
+ type CreateJourneyRequest as CreateJourneyRequest,
type Journey as Journey,
+ type JourneyAINode as JourneyAINode,
+ type JourneyAPIInvokeTriggerNode as JourneyAPIInvokeTriggerNode,
+ type JourneyConditionAtom as JourneyConditionAtom,
+ type JourneyConditionGroup as JourneyConditionGroup,
+ type JourneyConditionNestedGroup as JourneyConditionNestedGroup,
+ type JourneyConditionsField as JourneyConditionsField,
+ type JourneyDelayDurationNode as JourneyDelayDurationNode,
+ type JourneyDelayUntilNode as JourneyDelayUntilNode,
+ type JourneyExitNode as JourneyExitNode,
+ type JourneyFetchGetDeleteNode as JourneyFetchGetDeleteNode,
+ type JourneyFetchPostPutNode as JourneyFetchPostPutNode,
+ type JourneyMergeStrategy as JourneyMergeStrategy,
+ type JourneyNode as JourneyNode,
+ type JourneyPublishRequest as JourneyPublishRequest,
+ type JourneyResponse as JourneyResponse,
+ type JourneySegmentTriggerNode as JourneySegmentTriggerNode,
+ type JourneySendNode as JourneySendNode,
+ type JourneyState as JourneyState,
+ type JourneyTemplateCreateRequest as JourneyTemplateCreateRequest,
+ type JourneyTemplateGetResponse as JourneyTemplateGetResponse,
+ type JourneyTemplateListResponse as JourneyTemplateListResponse,
+ type JourneyTemplatePublishRequest as JourneyTemplatePublishRequest,
+ type JourneyTemplateReplaceRequest as JourneyTemplateReplaceRequest,
+ type JourneyTemplateSummary as JourneyTemplateSummary,
+ type JourneyThrottleDynamicNode as JourneyThrottleDynamicNode,
+ type JourneyThrottleStaticNode as JourneyThrottleStaticNode,
+ type JourneyVersionItem as JourneyVersionItem,
+ type JourneyVersionsListResponse as JourneyVersionsListResponse,
type JourneysInvokeRequest as JourneysInvokeRequest,
type JourneysInvokeResponse as JourneysInvokeResponse,
type JourneysListResponse as JourneysListResponse,
+ type JourneyCreateParams as JourneyCreateParams,
+ type JourneyRetrieveParams as JourneyRetrieveParams,
type JourneyListParams as JourneyListParams,
type JourneyInvokeParams as JourneyInvokeParams,
+ type JourneyPublishParams as JourneyPublishParams,
+ type JourneyReplaceParams as JourneyReplaceParams,
};
export {
diff --git a/src/internal/types.ts b/src/internal/types.ts
index b668dfc0..a050513a 100644
--- a/src/internal/types.ts
+++ b/src/internal/types.ts
@@ -40,7 +40,6 @@ type OverloadedParameters =
: T extends (...args: infer A) => unknown ? A
: never;
-/* eslint-disable */
/**
* These imports attempt to get types from a parent package's dependencies.
* Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which
@@ -63,19 +62,18 @@ type OverloadedParameters =
*
* [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition
*/
-/** @ts-ignore For users with \@types/node */
+/** @ts-ignore For users with \@types/node */ /* prettier-ignore */
type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny;
-/** @ts-ignore For users with undici */
+/** @ts-ignore For users with undici */ /* prettier-ignore */
type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny;
-/** @ts-ignore For users with \@types/bun */
+/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */
type BunRequestInit = globalThis.FetchRequestInit;
-/** @ts-ignore For users with node-fetch@2 */
+/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */
type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny;
-/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */
+/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */
type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny;
-/** @ts-ignore For users who use Deno */
+/** @ts-ignore For users who use Deno */ /* prettier-ignore */
type FetchRequestInit = NonNullable[1]>;
-/* eslint-enable */
type RequestInits =
| NotAny
diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts
index dbbb7b33..4ddc254a 100644
--- a/src/internal/utils/log.ts
+++ b/src/internal/utils/log.ts
@@ -107,6 +107,8 @@ export const formatRequestDetails = (details: {
name,
(
name.toLowerCase() === 'authorization' ||
+ name.toLowerCase() === 'api-key' ||
+ name.toLowerCase() === 'x-api-key' ||
name.toLowerCase() === 'cookie' ||
name.toLowerCase() === 'set-cookie'
) ?
diff --git a/src/resources/index.ts b/src/resources/index.ts
index 39e3d90d..66263e95 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -60,13 +60,46 @@ export {
export { Inbound, type InboundTrackEventResponse, type InboundTrackEventParams } from './inbound';
export {
Journeys,
+ type CreateJourneyRequest,
type Journey,
+ type JourneyAINode,
+ type JourneyAPIInvokeTriggerNode,
+ type JourneyConditionAtom,
+ type JourneyConditionGroup,
+ type JourneyConditionNestedGroup,
+ type JourneyConditionsField,
+ type JourneyDelayDurationNode,
+ type JourneyDelayUntilNode,
+ type JourneyExitNode,
+ type JourneyFetchGetDeleteNode,
+ type JourneyFetchPostPutNode,
+ type JourneyMergeStrategy,
+ type JourneyNode,
+ type JourneyPublishRequest,
+ type JourneyResponse,
+ type JourneySegmentTriggerNode,
+ type JourneySendNode,
+ type JourneyState,
+ type JourneyTemplateCreateRequest,
+ type JourneyTemplateGetResponse,
+ type JourneyTemplateListResponse,
+ type JourneyTemplatePublishRequest,
+ type JourneyTemplateReplaceRequest,
+ type JourneyTemplateSummary,
+ type JourneyThrottleDynamicNode,
+ type JourneyThrottleStaticNode,
+ type JourneyVersionItem,
+ type JourneyVersionsListResponse,
type JourneysInvokeRequest,
type JourneysInvokeResponse,
type JourneysListResponse,
+ type JourneyCreateParams,
+ type JourneyRetrieveParams,
type JourneyListParams,
type JourneyInvokeParams,
-} from './journeys';
+ type JourneyPublishParams,
+ type JourneyReplaceParams,
+} from './journeys/journeys';
export {
Lists,
type PutSubscriptionsRecipient,
diff --git a/src/resources/journeys.ts b/src/resources/journeys.ts
index a7157480..24b7a0b2 100644
--- a/src/resources/journeys.ts
+++ b/src/resources/journeys.ts
@@ -1,174 +1,3 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { APIResource } from '../core/resource';
-import { APIPromise } from '../core/api-promise';
-import { RequestOptions } from '../internal/request-options';
-import { path } from '../internal/utils/path';
-
-export class Journeys extends APIResource {
- /**
- * Get the list of journeys.
- *
- * @example
- * ```ts
- * const journeysListResponse = await client.journeys.list();
- * ```
- */
- list(
- query: JourneyListParams | null | undefined = {},
- options?: RequestOptions,
- ): APIPromise {
- return this._client.get('/journeys', { query, ...options });
- }
-
- /**
- * Invoke a journey run from a journey template.
- *
- * @example
- * ```ts
- * const journeysInvokeResponse = await client.journeys.invoke(
- * 'templateId',
- * {
- * data: { order_id: 'order-456', amount: 99.99 },
- * user_id: 'user-123',
- * },
- * );
- * ```
- */
- invoke(
- templateID: string,
- body: JourneyInvokeParams,
- options?: RequestOptions,
- ): APIPromise {
- return this._client.post(path`/journeys/${templateID}/invoke`, { body, ...options });
- }
-}
-
-/**
- * A journey template representing an automation workflow.
- */
-export interface Journey {
- /**
- * The unique identifier of the journey.
- */
- id: string;
-
- /**
- * The name of the journey.
- */
- name: string;
-
- /**
- * The version of the journey (published or draft).
- */
- version: 'published' | 'draft';
-
- /**
- * ISO 8601 timestamp when the journey was created.
- */
- createdAt?: string;
-
- /**
- * ISO 8601 timestamp when the journey was last updated.
- */
- updatedAt?: string;
-}
-
-/**
- * Request body for invoking a journey. Requires either a user identifier or a
- * profile with contact information. User identifiers can be provided via user_id
- * field, or resolved from profile/data objects (user_id, userId, or anonymousId
- * fields).
- */
-export interface JourneysInvokeRequest {
- /**
- * Data payload passed to the journey. The expected shape can be predefined using
- * the schema builder in the journey editor. This data is available in journey
- * steps for condition evaluation and template variable interpolation. Can also
- * contain user identifiers (user_id, userId, anonymousId) if not provided
- * elsewhere.
- */
- data?: { [key: string]: unknown };
-
- /**
- * Profile data for the user. Can contain contact information (email,
- * phone_number), user identifiers (user_id, userId, anonymousId), or any custom
- * profile fields. Profile fields are merged with any existing stored profile for
- * the user. Include context.tenant_id to load a tenant-scoped profile for
- * multi-tenant scenarios.
- */
- profile?: { [key: string]: unknown };
-
- /**
- * A unique identifier for the user. If not provided, the system will attempt to
- * resolve the user identifier from profile or data objects.
- */
- user_id?: string;
-}
-
-export interface JourneysInvokeResponse {
- /**
- * A unique identifier for the journey run that was created.
- */
- runId: string;
-}
-
-export interface JourneysListResponse {
- /**
- * A cursor token for pagination. Present when there are more results available.
- */
- cursor?: string;
-
- templates?: Array;
-}
-
-export interface JourneyListParams {
- /**
- * A cursor token for pagination. Use the cursor from the previous response to
- * fetch the next page of results.
- */
- cursor?: string;
-
- /**
- * The version of journeys to retrieve. Accepted values are published (for
- * published journeys) or draft (for draft journeys). Defaults to published.
- */
- version?: 'published' | 'draft';
-}
-
-export interface JourneyInvokeParams {
- /**
- * Data payload passed to the journey. The expected shape can be predefined using
- * the schema builder in the journey editor. This data is available in journey
- * steps for condition evaluation and template variable interpolation. Can also
- * contain user identifiers (user_id, userId, anonymousId) if not provided
- * elsewhere.
- */
- data?: { [key: string]: unknown };
-
- /**
- * Profile data for the user. Can contain contact information (email,
- * phone_number), user identifiers (user_id, userId, anonymousId), or any custom
- * profile fields. Profile fields are merged with any existing stored profile for
- * the user. Include context.tenant_id to load a tenant-scoped profile for
- * multi-tenant scenarios.
- */
- profile?: { [key: string]: unknown };
-
- /**
- * A unique identifier for the user. If not provided, the system will attempt to
- * resolve the user identifier from profile or data objects.
- */
- user_id?: string;
-}
-
-export declare namespace Journeys {
- export {
- type Journey as Journey,
- type JourneysInvokeRequest as JourneysInvokeRequest,
- type JourneysInvokeResponse as JourneysInvokeResponse,
- type JourneysListResponse as JourneysListResponse,
- type JourneyListParams as JourneyListParams,
- type JourneyInvokeParams as JourneyInvokeParams,
- };
-}
+export * from './journeys/index';
diff --git a/src/resources/journeys/index.ts b/src/resources/journeys/index.ts
new file mode 100644
index 00000000..3217441f
--- /dev/null
+++ b/src/resources/journeys/index.ts
@@ -0,0 +1,54 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export {
+ Journeys,
+ type CreateJourneyRequest,
+ type Journey,
+ type JourneyAINode,
+ type JourneyAPIInvokeTriggerNode,
+ type JourneyConditionAtom,
+ type JourneyConditionGroup,
+ type JourneyConditionNestedGroup,
+ type JourneyConditionsField,
+ type JourneyDelayDurationNode,
+ type JourneyDelayUntilNode,
+ type JourneyExitNode,
+ type JourneyFetchGetDeleteNode,
+ type JourneyFetchPostPutNode,
+ type JourneyMergeStrategy,
+ type JourneyNode,
+ type JourneyPublishRequest,
+ type JourneyResponse,
+ type JourneySegmentTriggerNode,
+ type JourneySendNode,
+ type JourneyState,
+ type JourneyTemplateCreateRequest,
+ type JourneyTemplateGetResponse,
+ type JourneyTemplateListResponse,
+ type JourneyTemplatePublishRequest,
+ type JourneyTemplateReplaceRequest,
+ type JourneyTemplateSummary,
+ type JourneyThrottleDynamicNode,
+ type JourneyThrottleStaticNode,
+ type JourneyVersionItem,
+ type JourneyVersionsListResponse,
+ type JourneysInvokeRequest,
+ type JourneysInvokeResponse,
+ type JourneysListResponse,
+ type JourneyCreateParams,
+ type JourneyRetrieveParams,
+ type JourneyListParams,
+ type JourneyInvokeParams,
+ type JourneyPublishParams,
+ type JourneyReplaceParams,
+} from './journeys';
+export {
+ Templates,
+ type TemplateCreateParams,
+ type TemplateRetrieveParams,
+ type TemplateListParams,
+ type TemplateArchiveParams,
+ type TemplateListVersionsParams,
+ type TemplatePublishParams,
+ type TemplateReplaceParams,
+} from './templates';
diff --git a/src/resources/journeys/journeys.ts b/src/resources/journeys/journeys.ts
new file mode 100644
index 00000000..d0666e5a
--- /dev/null
+++ b/src/resources/journeys/journeys.ts
@@ -0,0 +1,939 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as JourneysAPI from './journeys';
+import * as Shared from '../shared';
+import * as TemplatesAPI from './templates';
+import {
+ TemplateArchiveParams,
+ TemplateCreateParams,
+ TemplateListParams,
+ TemplateListVersionsParams,
+ TemplatePublishParams,
+ TemplateReplaceParams,
+ TemplateRetrieveParams,
+ Templates,
+} from './templates';
+import { APIPromise } from '../../core/api-promise';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Journeys extends APIResource {
+ templates: TemplatesAPI.Templates = new TemplatesAPI.Templates(this._client);
+
+ /**
+ * Create a new journey. The journey is created in DRAFT state. Use POST
+ * /journeys/{templateId}/publish to make it live.
+ *
+ * @example
+ * ```ts
+ * const journeyResponse = await client.journeys.create({
+ * name: 'Welcome Journey',
+ * nodes: [
+ * {
+ * id: 'trigger-1',
+ * type: 'trigger',
+ * trigger_type: 'api',
+ * },
+ * { id: 'send-1', type: 'send' },
+ * ],
+ * enabled: true,
+ * state: 'DRAFT',
+ * });
+ * ```
+ */
+ create(body: JourneyCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/journeys', { body, ...options });
+ }
+
+ /**
+ * Fetch a journey by id. Pass `?version=draft` (default `published`) to retrieve
+ * the working draft, or `?version=vN` to retrieve a historical version.
+ *
+ * @example
+ * ```ts
+ * const journeyResponse = await client.journeys.retrieve('x');
+ * ```
+ */
+ retrieve(
+ templateID: string,
+ query: JourneyRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get(path`/journeys/${templateID}`, { query, ...options });
+ }
+
+ /**
+ * Get the list of journeys.
+ *
+ * @example
+ * ```ts
+ * const journeysListResponse = await client.journeys.list();
+ * ```
+ */
+ list(
+ query: JourneyListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/journeys', { query, ...options });
+ }
+
+ /**
+ * Archive a journey. Archived journeys cannot be invoked. Existing journey runs
+ * continue to completion.
+ *
+ * @example
+ * ```ts
+ * await client.journeys.archive('x');
+ * ```
+ */
+ archive(templateID: string, options?: RequestOptions): APIPromise {
+ return this._client.delete(path`/journeys/${templateID}`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * Invoke a journey run from a journey template.
+ *
+ * @example
+ * ```ts
+ * const journeysInvokeResponse = await client.journeys.invoke(
+ * 'templateId',
+ * {
+ * data: { order_id: 'order-456', amount: 99.99 },
+ * user_id: 'user-123',
+ * },
+ * );
+ * ```
+ */
+ invoke(
+ templateID: string,
+ body: JourneyInvokeParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/journeys/${templateID}/invoke`, { body, ...options });
+ }
+
+ /**
+ * List published versions of a journey, ordered most recent first.
+ *
+ * @example
+ * ```ts
+ * const journeyVersionsListResponse =
+ * await client.journeys.listVersions('x');
+ * ```
+ */
+ listVersions(templateID: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/journeys/${templateID}/versions`, options);
+ }
+
+ /**
+ * Publish the current draft as a new version. Optionally rollback to a prior
+ * version by passing `{ version: 'vN' }`.
+ *
+ * @example
+ * ```ts
+ * const journeyResponse = await client.journeys.publish('x');
+ * ```
+ */
+ publish(
+ templateID: string,
+ body: JourneyPublishParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/journeys/${templateID}/publish`, { body, ...options });
+ }
+
+ /**
+ * Replace the journey draft. Updates the working draft only; call POST
+ * /journeys/{templateId}/publish to make it live.
+ *
+ * @example
+ * ```ts
+ * const journeyResponse = await client.journeys.replace('x', {
+ * name: 'Welcome Journey v2',
+ * nodes: [],
+ * enabled: true,
+ * state: 'DRAFT',
+ * });
+ * ```
+ */
+ replace(
+ templateID: string,
+ body: JourneyReplaceParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.put(path`/journeys/${templateID}`, { body, ...options });
+ }
+}
+
+export interface CreateJourneyRequest {
+ name: string;
+
+ nodes: Array;
+
+ enabled?: boolean;
+
+ state?: JourneyState;
+}
+
+/**
+ * A journey template representing an automation workflow.
+ */
+export interface Journey {
+ /**
+ * The unique identifier of the journey.
+ */
+ id: string;
+
+ /**
+ * The name of the journey.
+ */
+ name: string;
+
+ /**
+ * The version of the journey (published or draft).
+ */
+ version: 'published' | 'draft';
+
+ /**
+ * ISO 8601 timestamp when the journey was created.
+ */
+ createdAt?: string;
+
+ /**
+ * ISO 8601 timestamp when the journey was last updated.
+ */
+ updatedAt?: string;
+}
+
+export interface JourneyAINode {
+ /**
+ * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv.
+ */
+ output_schema: { [key: string]: unknown };
+
+ type: 'ai';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+
+ model?: string;
+
+ user_prompt?: string;
+
+ web_search?: boolean;
+}
+
+export interface JourneyAPIInvokeTriggerNode {
+ trigger_type: 'api-invoke';
+
+ type: 'trigger';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+
+ /**
+ * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv.
+ */
+ schema?: { [key: string]: unknown };
+}
+
+/**
+ * A single condition expressed as a positional tuple of strings.
+ *
+ * - Binary form (3 elements): `[path, operator, value]` where `operator` is one of
+ * `is equal`, `is not equal`, `contains`, `does not contain`, `starts with`,
+ * `ends with`, `greater than`, `greater than or equal`, `less than`,
+ * `less than or equal`.
+ *
+ * Example: `["user.tier", "is equal", "gold"]`.
+ *
+ * - Unary form (2 elements): `[path, operator]` where `operator` is one of
+ * `exists`, `does not exist`.
+ *
+ * Example: `["user.email", "exists"]`.
+ *
+ * The first element is a non-empty dot-path. The second element is the operator
+ * (must come from one of the two operator sets above). For the binary form, the
+ * third element is the comparison value (string). Runtime validation of the
+ * operator value and arity is performed by the backend; SDKs surface this as a
+ * string list.
+ */
+export type JourneyConditionAtom = Array;
+
+/**
+ * A leaf condition group. Exactly one of `AND` or `OR` must be present at runtime;
+ * each is a list of `JourneyConditionAtom` tuples.
+ */
+export interface JourneyConditionGroup {
+ AND?: Array;
+
+ OR?: Array;
+}
+
+/**
+ * A nested condition group. Exactly one of `AND` or `OR` must be present at
+ * runtime; each is a list of `JourneyConditionGroup` items.
+ */
+export interface JourneyConditionNestedGroup {
+ AND?: Array;
+
+ OR?: Array;
+}
+
+/**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+export type JourneyConditionsField =
+ | JourneyConditionAtom
+ | JourneyConditionGroup
+ | JourneyConditionNestedGroup;
+
+export interface JourneyDelayDurationNode {
+ duration: string;
+
+ mode: 'duration';
+
+ type: 'delay';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+}
+
+export interface JourneyDelayUntilNode {
+ mode: 'until';
+
+ type: 'delay';
+
+ until: string;
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+}
+
+export interface JourneyExitNode {
+ type: 'exit';
+
+ id?: string;
+}
+
+export interface JourneyFetchGetDeleteNode {
+ merge_strategy: JourneyMergeStrategy;
+
+ method: 'get' | 'delete';
+
+ type: 'fetch';
+
+ url: string;
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+
+ headers?: { [key: string]: string };
+
+ query_params?: { [key: string]: string };
+
+ /**
+ * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv.
+ */
+ response_schema?: { [key: string]: unknown };
+}
+
+export interface JourneyFetchPostPutNode {
+ merge_strategy: JourneyMergeStrategy;
+
+ method: 'post' | 'put';
+
+ type: 'fetch';
+
+ url: string;
+
+ id?: string;
+
+ body?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+
+ headers?: { [key: string]: string };
+
+ query_params?: { [key: string]: string };
+
+ /**
+ * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv.
+ */
+ response_schema?: { [key: string]: unknown };
+}
+
+export type JourneyMergeStrategy = 'overwrite' | 'soft-merge' | 'replace' | 'none';
+
+/**
+ * A single node in a journey DAG. Discriminated by `type` plus a secondary
+ * discriminator on some variants (`trigger_type` for trigger, `mode` for delay,
+ * `method` for fetch, `scope` for throttle). Each variant is exported as a
+ * separate schema for SDK type quality.
+ */
+export type JourneyNode =
+ | JourneyAPIInvokeTriggerNode
+ | JourneySegmentTriggerNode
+ | JourneySendNode
+ | JourneyDelayDurationNode
+ | JourneyDelayUntilNode
+ | JourneyFetchGetDeleteNode
+ | JourneyFetchPostPutNode
+ | JourneyAINode
+ | JourneyThrottleStaticNode
+ | JourneyThrottleDynamicNode
+ | JourneyExitNode
+ | JourneyNode.JourneyBranchNode;
+
+export namespace JourneyNode {
+ /**
+ * Branch node. Routes to one of `paths[]` whose `conditions` match, else falls
+ * through to `default.nodes`. Inlined rather than referenced so the recursive
+ * `nodes: JourneyNode[]` cycle stays within a single generated module (Stainless
+ * Python forward-ref resolution does not span modules well for this recursion
+ * shape).
+ */
+ export interface JourneyBranchNode {
+ default: JourneyBranchNode.Default;
+
+ paths: Array;
+
+ type: 'branch';
+
+ id?: string;
+ }
+
+ export namespace JourneyBranchNode {
+ export interface Default {
+ nodes: Array;
+
+ label?: string;
+ }
+
+ export interface Path {
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions: JourneysAPI.JourneyConditionsField;
+
+ nodes: Array;
+
+ label?: string;
+ }
+ }
+}
+
+export interface JourneyPublishRequest {
+ version?: string;
+}
+
+export interface JourneyResponse {
+ id: string;
+
+ created: number | null;
+
+ creator: string | null;
+
+ enabled: boolean;
+
+ name: string;
+
+ nodes: Array;
+
+ published: number | null;
+
+ state: JourneyState;
+
+ updated: number | null;
+
+ updater: string | null;
+}
+
+export interface JourneySegmentTriggerNode {
+ request_type: 'identify' | 'group' | 'track';
+
+ trigger_type: 'segment';
+
+ type: 'trigger';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+
+ event_id?: string;
+}
+
+export interface JourneySendNode {
+ message: JourneySendNode.Message;
+
+ type: 'send';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+}
+
+export namespace JourneySendNode {
+ export interface Message {
+ template: string;
+
+ data?: { [key: string]: unknown };
+
+ delay?: Message.Delay;
+
+ to?: Message.To;
+ }
+
+ export namespace Message {
+ export interface Delay {
+ until: string;
+
+ timezone?: string;
+ }
+
+ export interface To {
+ email_override?: string;
+
+ phone_number_override?: string;
+
+ user_id_override?: string;
+ }
+ }
+}
+
+export type JourneyState = 'DRAFT' | 'PUBLISHED';
+
+export interface JourneyTemplateCreateRequest {
+ channel: string;
+
+ notification: JourneyTemplateCreateRequest.Notification;
+
+ providerKey?: string;
+
+ state?: string;
+}
+
+export namespace JourneyTemplateCreateRequest {
+ export interface Notification {
+ brand: Notification.Brand | null;
+
+ content: Notification.Content;
+
+ name: string;
+
+ subscription: Notification.Subscription | null;
+
+ tags: Array;
+ }
+
+ export namespace Notification {
+ export interface Brand {
+ id: string;
+ }
+
+ export interface Content {
+ elements: Array;
+
+ version: '2022-01-01';
+
+ scope?: 'default' | 'strict';
+ }
+
+ export interface Subscription {
+ topic_id: string;
+ }
+ }
+}
+
+export interface JourneyTemplateGetResponse {
+ id: string;
+
+ brand: JourneyTemplateGetResponse.Brand | null;
+
+ content: JourneyTemplateGetResponse.Content;
+
+ created: number;
+
+ creator: string;
+
+ name: string;
+
+ state: 'DRAFT' | 'PUBLISHED';
+
+ subscription: JourneyTemplateGetResponse.Subscription | null;
+
+ tags: Array;
+
+ updated?: number;
+
+ updater?: string;
+}
+
+export namespace JourneyTemplateGetResponse {
+ export interface Brand {
+ id: string;
+ }
+
+ export interface Content {
+ elements: Array;
+
+ version: '2022-01-01';
+
+ scope?: 'default' | 'strict';
+ }
+
+ export interface Subscription {
+ topic_id: string;
+ }
+}
+
+export interface JourneyTemplateListResponse {
+ paging: Shared.Paging;
+
+ results: Array;
+}
+
+export interface JourneyTemplatePublishRequest {
+ version?: string;
+}
+
+export interface JourneyTemplateReplaceRequest {
+ notification: JourneyTemplateReplaceRequest.Notification;
+
+ state?: string;
+}
+
+export namespace JourneyTemplateReplaceRequest {
+ export interface Notification {
+ brand: Notification.Brand | null;
+
+ content: Notification.Content;
+
+ name: string;
+
+ subscription: Notification.Subscription | null;
+
+ tags: Array;
+ }
+
+ export namespace Notification {
+ export interface Brand {
+ id: string;
+ }
+
+ export interface Content {
+ elements: Array;
+
+ version: '2022-01-01';
+
+ scope?: 'default' | 'strict';
+ }
+
+ export interface Subscription {
+ topic_id: string;
+ }
+ }
+}
+
+export interface JourneyTemplateSummary {
+ id: string;
+
+ created: number;
+
+ creator: string;
+
+ name: string;
+
+ state: string;
+
+ tags: Array;
+
+ updated?: number;
+
+ updater?: string;
+}
+
+export interface JourneyThrottleDynamicNode {
+ max_allowed: number;
+
+ period: string;
+
+ scope: 'dynamic';
+
+ throttle_key: string;
+
+ type: 'throttle';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+}
+
+export interface JourneyThrottleStaticNode {
+ max_allowed: number;
+
+ period: string;
+
+ scope: 'user' | 'global';
+
+ type: 'throttle';
+
+ id?: string;
+
+ /**
+ * Condition spec for a journey node. Accepts a single condition atom, an AND/OR
+ * group, or an AND/OR nested group. Omit the `conditions` property entirely to
+ * express "no conditions".
+ */
+ conditions?: JourneyConditionsField;
+}
+
+export interface JourneyVersionItem {
+ created: number | null;
+
+ creator: string | null;
+
+ name: string;
+
+ published: number | null;
+
+ version: string;
+}
+
+export interface JourneyVersionsListResponse {
+ paging: Shared.Paging;
+
+ results: Array;
+}
+
+/**
+ * Request body for invoking a journey. Requires either a user identifier or a
+ * profile with contact information. User identifiers can be provided via user_id
+ * field, or resolved from profile/data objects (user_id, userId, or anonymousId
+ * fields).
+ */
+export interface JourneysInvokeRequest {
+ /**
+ * Data payload passed to the journey. The expected shape can be predefined using
+ * the schema builder in the journey editor. This data is available in journey
+ * steps for condition evaluation and template variable interpolation. Can also
+ * contain user identifiers (user_id, userId, anonymousId) if not provided
+ * elsewhere.
+ */
+ data?: { [key: string]: unknown };
+
+ /**
+ * Profile data for the user. Can contain contact information (email,
+ * phone_number), user identifiers (user_id, userId, anonymousId), or any custom
+ * profile fields. Profile fields are merged with any existing stored profile for
+ * the user. Include context.tenant_id to load a tenant-scoped profile for
+ * multi-tenant scenarios.
+ */
+ profile?: { [key: string]: unknown };
+
+ /**
+ * A unique identifier for the user. If not provided, the system will attempt to
+ * resolve the user identifier from profile or data objects.
+ */
+ user_id?: string;
+}
+
+export interface JourneysInvokeResponse {
+ /**
+ * A unique identifier for the journey run that was created.
+ */
+ runId: string;
+}
+
+export interface JourneysListResponse {
+ /**
+ * A cursor token for pagination. Present when there are more results available.
+ */
+ cursor?: string;
+
+ templates?: Array;
+}
+
+export interface JourneyCreateParams {
+ name: string;
+
+ nodes: Array;
+
+ enabled?: boolean;
+
+ state?: JourneyState;
+}
+
+export interface JourneyRetrieveParams {
+ version?: string;
+}
+
+export interface JourneyListParams {
+ /**
+ * A cursor token for pagination. Use the cursor from the previous response to
+ * fetch the next page of results.
+ */
+ cursor?: string;
+
+ /**
+ * The version of journeys to retrieve. Accepted values are published (for
+ * published journeys) or draft (for draft journeys). Defaults to published.
+ */
+ version?: 'published' | 'draft';
+}
+
+export interface JourneyInvokeParams {
+ /**
+ * Data payload passed to the journey. The expected shape can be predefined using
+ * the schema builder in the journey editor. This data is available in journey
+ * steps for condition evaluation and template variable interpolation. Can also
+ * contain user identifiers (user_id, userId, anonymousId) if not provided
+ * elsewhere.
+ */
+ data?: { [key: string]: unknown };
+
+ /**
+ * Profile data for the user. Can contain contact information (email,
+ * phone_number), user identifiers (user_id, userId, anonymousId), or any custom
+ * profile fields. Profile fields are merged with any existing stored profile for
+ * the user. Include context.tenant_id to load a tenant-scoped profile for
+ * multi-tenant scenarios.
+ */
+ profile?: { [key: string]: unknown };
+
+ /**
+ * A unique identifier for the user. If not provided, the system will attempt to
+ * resolve the user identifier from profile or data objects.
+ */
+ user_id?: string;
+}
+
+export interface JourneyPublishParams {
+ version?: string;
+}
+
+export interface JourneyReplaceParams {
+ name: string;
+
+ nodes: Array;
+
+ enabled?: boolean;
+
+ state?: JourneyState;
+}
+
+Journeys.Templates = Templates;
+
+export declare namespace Journeys {
+ export {
+ type CreateJourneyRequest as CreateJourneyRequest,
+ type Journey as Journey,
+ type JourneyAINode as JourneyAINode,
+ type JourneyAPIInvokeTriggerNode as JourneyAPIInvokeTriggerNode,
+ type JourneyConditionAtom as JourneyConditionAtom,
+ type JourneyConditionGroup as JourneyConditionGroup,
+ type JourneyConditionNestedGroup as JourneyConditionNestedGroup,
+ type JourneyConditionsField as JourneyConditionsField,
+ type JourneyDelayDurationNode as JourneyDelayDurationNode,
+ type JourneyDelayUntilNode as JourneyDelayUntilNode,
+ type JourneyExitNode as JourneyExitNode,
+ type JourneyFetchGetDeleteNode as JourneyFetchGetDeleteNode,
+ type JourneyFetchPostPutNode as JourneyFetchPostPutNode,
+ type JourneyMergeStrategy as JourneyMergeStrategy,
+ type JourneyNode as JourneyNode,
+ type JourneyPublishRequest as JourneyPublishRequest,
+ type JourneyResponse as JourneyResponse,
+ type JourneySegmentTriggerNode as JourneySegmentTriggerNode,
+ type JourneySendNode as JourneySendNode,
+ type JourneyState as JourneyState,
+ type JourneyTemplateCreateRequest as JourneyTemplateCreateRequest,
+ type JourneyTemplateGetResponse as JourneyTemplateGetResponse,
+ type JourneyTemplateListResponse as JourneyTemplateListResponse,
+ type JourneyTemplatePublishRequest as JourneyTemplatePublishRequest,
+ type JourneyTemplateReplaceRequest as JourneyTemplateReplaceRequest,
+ type JourneyTemplateSummary as JourneyTemplateSummary,
+ type JourneyThrottleDynamicNode as JourneyThrottleDynamicNode,
+ type JourneyThrottleStaticNode as JourneyThrottleStaticNode,
+ type JourneyVersionItem as JourneyVersionItem,
+ type JourneyVersionsListResponse as JourneyVersionsListResponse,
+ type JourneysInvokeRequest as JourneysInvokeRequest,
+ type JourneysInvokeResponse as JourneysInvokeResponse,
+ type JourneysListResponse as JourneysListResponse,
+ type JourneyCreateParams as JourneyCreateParams,
+ type JourneyRetrieveParams as JourneyRetrieveParams,
+ type JourneyListParams as JourneyListParams,
+ type JourneyInvokeParams as JourneyInvokeParams,
+ type JourneyPublishParams as JourneyPublishParams,
+ type JourneyReplaceParams as JourneyReplaceParams,
+ };
+
+ export {
+ Templates as Templates,
+ type TemplateCreateParams as TemplateCreateParams,
+ type TemplateRetrieveParams as TemplateRetrieveParams,
+ type TemplateListParams as TemplateListParams,
+ type TemplateArchiveParams as TemplateArchiveParams,
+ type TemplateListVersionsParams as TemplateListVersionsParams,
+ type TemplatePublishParams as TemplatePublishParams,
+ type TemplateReplaceParams as TemplateReplaceParams,
+ };
+}
diff --git a/src/resources/journeys/templates.ts b/src/resources/journeys/templates.ts
new file mode 100644
index 00000000..7e35922c
--- /dev/null
+++ b/src/resources/journeys/templates.ts
@@ -0,0 +1,310 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as Shared from '../shared';
+import * as JourneysAPI from './journeys';
+import * as NotificationsAPI from '../notifications/notifications';
+import { APIPromise } from '../../core/api-promise';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Templates extends APIResource {
+ /**
+ * Create a notification template scoped to this journey. The template is created
+ * in DRAFT state.
+ *
+ * @example
+ * ```ts
+ * const journeyTemplateGetResponse =
+ * await client.journeys.templates.create('x', {
+ * channel: 'email',
+ * notification: {
+ * name: 'Welcome email',
+ * tags: [],
+ * brand: null,
+ * subscription: null,
+ * content: {
+ * version: '2022-01-01',
+ * elements: [{ type: 'text' }],
+ * },
+ * },
+ * });
+ * ```
+ */
+ create(
+ templateID: string,
+ body: TemplateCreateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/journeys/${templateID}/templates`, { body, ...options });
+ }
+
+ /**
+ * Fetch a journey-scoped notification template by id. Pass `?version=draft`
+ * (default `published`) to retrieve the working draft, or `?version=vN` for a
+ * historical version.
+ *
+ * @example
+ * ```ts
+ * const journeyTemplateGetResponse =
+ * await client.journeys.templates.retrieve('x', {
+ * templateId: 'x',
+ * });
+ * ```
+ */
+ retrieve(
+ notificationID: string,
+ params: TemplateRetrieveParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { templateId } = params;
+ return this._client.get(path`/journeys/${templateId}/templates/${notificationID}`, options);
+ }
+
+ /**
+ * List notification templates scoped to this journey. Templates scoped to a
+ * journey can only be referenced from `send` nodes of the same journey.
+ *
+ * @example
+ * ```ts
+ * const journeyTemplateListResponse =
+ * await client.journeys.templates.list('x');
+ * ```
+ */
+ list(
+ templateID: string,
+ query: TemplateListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get(path`/journeys/${templateID}/templates`, { query, ...options });
+ }
+
+ /**
+ * Archive a journey-scoped notification template. Archived templates cannot be
+ * sent.
+ *
+ * @example
+ * ```ts
+ * await client.journeys.templates.archive('x', {
+ * templateId: 'x',
+ * });
+ * ```
+ */
+ archive(notificationID: string, params: TemplateArchiveParams, options?: RequestOptions): APIPromise {
+ const { templateId } = params;
+ return this._client.delete(path`/journeys/${templateId}/templates/${notificationID}`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * List published versions of a journey-scoped notification template, ordered most
+ * recent first.
+ *
+ * @example
+ * ```ts
+ * const notificationTemplateVersionListResponse =
+ * await client.journeys.templates.listVersions('x', {
+ * templateId: 'x',
+ * });
+ * ```
+ */
+ listVersions(
+ notificationID: string,
+ params: TemplateListVersionsParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { templateId } = params;
+ return this._client.get(path`/journeys/${templateId}/templates/${notificationID}/versions`, options);
+ }
+
+ /**
+ * Publish the current draft of a journey-scoped notification template.
+ *
+ * @example
+ * ```ts
+ * await client.journeys.templates.publish('x', {
+ * templateId: 'x',
+ * });
+ * ```
+ */
+ publish(notificationID: string, params: TemplatePublishParams, options?: RequestOptions): APIPromise {
+ const { templateId, ...body } = params;
+ return this._client.post(path`/journeys/${templateId}/templates/${notificationID}/publish`, {
+ body,
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * Replace a journey-scoped notification template draft.
+ *
+ * @example
+ * ```ts
+ * const journeyTemplateGetResponse =
+ * await client.journeys.templates.replace('x', {
+ * templateId: 'x',
+ * notification: {
+ * brand: { id: 'id' },
+ * content: { elements: [{}], version: '2022-01-01' },
+ * name: 'name',
+ * subscription: { topic_id: 'topic_id' },
+ * tags: ['string'],
+ * },
+ * });
+ * ```
+ */
+ replace(
+ notificationID: string,
+ params: TemplateReplaceParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { templateId, ...body } = params;
+ return this._client.put(path`/journeys/${templateId}/templates/${notificationID}`, { body, ...options });
+ }
+}
+
+export interface TemplateCreateParams {
+ channel: string;
+
+ notification: TemplateCreateParams.Notification;
+
+ providerKey?: string;
+
+ state?: string;
+}
+
+export namespace TemplateCreateParams {
+ export interface Notification {
+ brand: Notification.Brand | null;
+
+ content: Notification.Content;
+
+ name: string;
+
+ subscription: Notification.Subscription | null;
+
+ tags: Array;
+ }
+
+ export namespace Notification {
+ export interface Brand {
+ id: string;
+ }
+
+ export interface Content {
+ elements: Array;
+
+ version: '2022-01-01';
+
+ scope?: 'default' | 'strict';
+ }
+
+ export interface Subscription {
+ topic_id: string;
+ }
+ }
+}
+
+export interface TemplateRetrieveParams {
+ /**
+ * Journey id
+ */
+ templateId: string;
+}
+
+export interface TemplateListParams {
+ cursor?: string;
+
+ limit?: number;
+}
+
+export interface TemplateArchiveParams {
+ /**
+ * Journey id
+ */
+ templateId: string;
+}
+
+export interface TemplateListVersionsParams {
+ /**
+ * Journey id
+ */
+ templateId: string;
+}
+
+export interface TemplatePublishParams {
+ /**
+ * Path param: Journey id
+ */
+ templateId: string;
+
+ /**
+ * Body param
+ */
+ version?: string;
+}
+
+export interface TemplateReplaceParams {
+ /**
+ * Path param: Journey id
+ */
+ templateId: string;
+
+ /**
+ * Body param
+ */
+ notification: TemplateReplaceParams.Notification;
+
+ /**
+ * Body param
+ */
+ state?: string;
+}
+
+export namespace TemplateReplaceParams {
+ export interface Notification {
+ brand: Notification.Brand | null;
+
+ content: Notification.Content;
+
+ name: string;
+
+ subscription: Notification.Subscription | null;
+
+ tags: Array;
+ }
+
+ export namespace Notification {
+ export interface Brand {
+ id: string;
+ }
+
+ export interface Content {
+ elements: Array;
+
+ version: '2022-01-01';
+
+ scope?: 'default' | 'strict';
+ }
+
+ export interface Subscription {
+ topic_id: string;
+ }
+ }
+}
+
+export declare namespace Templates {
+ export {
+ type TemplateCreateParams as TemplateCreateParams,
+ type TemplateRetrieveParams as TemplateRetrieveParams,
+ type TemplateListParams as TemplateListParams,
+ type TemplateArchiveParams as TemplateArchiveParams,
+ type TemplateListVersionsParams as TemplateListVersionsParams,
+ type TemplatePublishParams as TemplatePublishParams,
+ type TemplateReplaceParams as TemplateReplaceParams,
+ };
+}
diff --git a/src/resources/tenants/index.ts b/src/resources/tenants/index.ts
index c5216c97..8249babd 100644
--- a/src/resources/tenants/index.ts
+++ b/src/resources/tenants/index.ts
@@ -6,6 +6,7 @@ export {
type TemplateListResponse,
type TemplateRetrieveParams,
type TemplateListParams,
+ type TemplateDeleteParams,
type TemplatePublishParams,
type TemplateReplaceParams,
} from './templates/index';
diff --git a/src/resources/tenants/templates/index.ts b/src/resources/tenants/templates/index.ts
index d4f43150..f56deb7e 100644
--- a/src/resources/tenants/templates/index.ts
+++ b/src/resources/tenants/templates/index.ts
@@ -5,6 +5,7 @@ export {
type TemplateListResponse,
type TemplateRetrieveParams,
type TemplateListParams,
+ type TemplateDeleteParams,
type TemplatePublishParams,
type TemplateReplaceParams,
} from './templates';
diff --git a/src/resources/tenants/templates/templates.ts b/src/resources/tenants/templates/templates.ts
index 52e39d5b..262ca3d5 100644
--- a/src/resources/tenants/templates/templates.ts
+++ b/src/resources/tenants/templates/templates.ts
@@ -6,6 +6,7 @@ import * as TenantsAPI from '../tenants';
import * as VersionsAPI from './versions';
import { VersionRetrieveParams, Versions } from './versions';
import { APIPromise } from '../../../core/api-promise';
+import { buildHeaders } from '../../../internal/headers';
import { RequestOptions } from '../../../internal/request-options';
import { path } from '../../../internal/utils/path';
@@ -50,6 +51,29 @@ export class Templates extends APIResource {
return this._client.get(path`/tenants/${tenantID}/templates`, { query, ...options });
}
+ /**
+ * Deletes the tenant's notification template with the given `template_id`.
+ *
+ * Returns **204 No Content** with an empty body on success.
+ *
+ * Returns **404** if there is no template with this ID for the tenant, including a
+ * second `DELETE` after a successful removal.
+ *
+ * @example
+ * ```ts
+ * await client.tenants.templates.delete('template_id', {
+ * tenant_id: 'tenant_id',
+ * });
+ * ```
+ */
+ delete(templateID: string, params: TemplateDeleteParams, options?: RequestOptions): APIPromise {
+ const { tenant_id } = params;
+ return this._client.delete(path`/tenants/${tenant_id}/templates/${templateID}`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
/**
* Publishes a specific version of a notification template for a tenant.
*
@@ -174,6 +198,13 @@ export interface TemplateListParams {
limit?: number | null;
}
+export interface TemplateDeleteParams {
+ /**
+ * Id of the tenant that owns the template.
+ */
+ tenant_id: string;
+}
+
export interface TemplatePublishParams {
/**
* Path param: Id of the tenant that owns the template.
@@ -214,6 +245,7 @@ export declare namespace Templates {
type TemplateListResponse as TemplateListResponse,
type TemplateRetrieveParams as TemplateRetrieveParams,
type TemplateListParams as TemplateListParams,
+ type TemplateDeleteParams as TemplateDeleteParams,
type TemplatePublishParams as TemplatePublishParams,
type TemplateReplaceParams as TemplateReplaceParams,
};
diff --git a/src/resources/tenants/tenants.ts b/src/resources/tenants/tenants.ts
index 75aa7b31..1ac5e1f0 100644
--- a/src/resources/tenants/tenants.ts
+++ b/src/resources/tenants/tenants.ts
@@ -7,6 +7,7 @@ import * as PreferencesAPI from './preferences/preferences';
import { Preferences } from './preferences/preferences';
import * as TemplatesAPI from './templates/templates';
import {
+ TemplateDeleteParams,
TemplateListParams,
TemplateListResponse,
TemplatePublishParams,
@@ -463,6 +464,7 @@ export declare namespace Tenants {
type TemplateListResponse as TemplateListResponse,
type TemplateRetrieveParams as TemplateRetrieveParams,
type TemplateListParams as TemplateListParams,
+ type TemplateDeleteParams as TemplateDeleteParams,
type TemplatePublishParams as TemplatePublishParams,
type TemplateReplaceParams as TemplateReplaceParams,
};
diff --git a/src/version.ts b/src/version.ts
index 4533200e..c00d803e 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '7.10.2'; // x-release-please-version
+export const VERSION = '7.11.0'; // x-release-please-version
diff --git a/tests/api-resources/journeys.test.ts b/tests/api-resources/journeys.test.ts
deleted file mode 100644
index 92d4b7a5..00000000
--- a/tests/api-resources/journeys.test.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import Courier from '@trycourier/courier';
-
-const client = new Courier({
- apiKey: 'My API Key',
- baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
-});
-
-describe('resource journeys', () => {
- // Mock server tests are disabled
- test.skip('list', async () => {
- const responsePromise = client.journeys.list();
- const rawResponse = await responsePromise.asResponse();
- expect(rawResponse).toBeInstanceOf(Response);
- const response = await responsePromise;
- expect(response).not.toBeInstanceOf(Response);
- const dataAndResponse = await responsePromise.withResponse();
- expect(dataAndResponse.data).toBe(response);
- expect(dataAndResponse.response).toBe(rawResponse);
- });
-
- // Mock server tests are disabled
- test.skip('list: request options and params are passed correctly', async () => {
- // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
- await expect(
- client.journeys.list({ cursor: 'cursor', version: 'published' }, { path: '/_stainless_unknown_path' }),
- ).rejects.toThrow(Courier.NotFoundError);
- });
-
- // Mock server tests are disabled
- test.skip('invoke', async () => {
- const responsePromise = client.journeys.invoke('templateId', {});
- const rawResponse = await responsePromise.asResponse();
- expect(rawResponse).toBeInstanceOf(Response);
- const response = await responsePromise;
- expect(response).not.toBeInstanceOf(Response);
- const dataAndResponse = await responsePromise.withResponse();
- expect(dataAndResponse.data).toBe(response);
- expect(dataAndResponse.response).toBe(rawResponse);
- });
-});
diff --git a/tests/api-resources/journeys/journeys.test.ts b/tests/api-resources/journeys/journeys.test.ts
new file mode 100644
index 00000000..621004b7
--- /dev/null
+++ b/tests/api-resources/journeys/journeys.test.ts
@@ -0,0 +1,182 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import Courier from '@trycourier/courier';
+
+const client = new Courier({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource journeys', () => {
+ // Mock server tests are disabled
+ test.skip('create: only required params', async () => {
+ const responsePromise = client.journeys.create({
+ name: 'Welcome Journey',
+ nodes: [
+ { trigger_type: 'api-invoke', type: 'trigger' },
+ { trigger_type: 'api-invoke', type: 'trigger' },
+ ],
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('create: required and optional params', async () => {
+ const response = await client.journeys.create({
+ name: 'Welcome Journey',
+ nodes: [
+ {
+ trigger_type: 'api-invoke',
+ type: 'trigger',
+ id: 'trigger-1',
+ conditions: ['string', 'string'],
+ schema: { foo: 'bar' },
+ },
+ {
+ trigger_type: 'api-invoke',
+ type: 'trigger',
+ id: 'send-1',
+ conditions: ['string', 'string'],
+ schema: { foo: 'bar' },
+ },
+ ],
+ enabled: true,
+ state: 'DRAFT',
+ });
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve', async () => {
+ const responsePromise = client.journeys.retrieve('x');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.journeys.retrieve('x', { version: 'published' }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(Courier.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.journeys.list();
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.journeys.list({ cursor: 'cursor', version: 'published' }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(Courier.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('archive', async () => {
+ const responsePromise = client.journeys.archive('x');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('invoke', async () => {
+ const responsePromise = client.journeys.invoke('templateId', {});
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('listVersions', async () => {
+ const responsePromise = client.journeys.listVersions('x');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('publish', async () => {
+ const responsePromise = client.journeys.publish('x');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('publish: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.journeys.publish('x', { version: 'v321669910225' }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(Courier.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('replace: only required params', async () => {
+ const responsePromise = client.journeys.replace('x', {
+ name: 'Welcome Journey v2',
+ nodes: [{ trigger_type: 'api-invoke', type: 'trigger' }],
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('replace: required and optional params', async () => {
+ const response = await client.journeys.replace('x', {
+ name: 'Welcome Journey v2',
+ nodes: [
+ {
+ trigger_type: 'api-invoke',
+ type: 'trigger',
+ id: 'x',
+ conditions: ['string', 'string'],
+ schema: { foo: 'bar' },
+ },
+ ],
+ enabled: true,
+ state: 'DRAFT',
+ });
+ });
+});
diff --git a/tests/api-resources/journeys/templates.test.ts b/tests/api-resources/journeys/templates.test.ts
new file mode 100644
index 00000000..608e7141
--- /dev/null
+++ b/tests/api-resources/journeys/templates.test.ts
@@ -0,0 +1,202 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import Courier from '@trycourier/courier';
+
+const client = new Courier({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource templates', () => {
+ // Mock server tests are disabled
+ test.skip('create: only required params', async () => {
+ const responsePromise = client.journeys.templates.create('x', {
+ channel: 'email',
+ notification: {
+ brand: { id: 'id' },
+ content: { elements: [{}], version: '2022-01-01' },
+ name: 'Welcome email',
+ subscription: { topic_id: 'topic_id' },
+ tags: ['string'],
+ },
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('create: required and optional params', async () => {
+ const response = await client.journeys.templates.create('x', {
+ channel: 'email',
+ notification: {
+ brand: { id: 'id' },
+ content: {
+ elements: [
+ {
+ channels: ['string'],
+ if: 'if',
+ loop: 'loop',
+ ref: 'ref',
+ type: 'text',
+ },
+ ],
+ version: '2022-01-01',
+ scope: 'default',
+ },
+ name: 'Welcome email',
+ subscription: { topic_id: 'topic_id' },
+ tags: ['string'],
+ },
+ providerKey: 'x',
+ state: 'state',
+ });
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve: only required params', async () => {
+ const responsePromise = client.journeys.templates.retrieve('x', { templateId: 'x' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve: required and optional params', async () => {
+ const response = await client.journeys.templates.retrieve('x', { templateId: 'x' });
+ });
+
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.journeys.templates.list('x');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.journeys.templates.list(
+ 'x',
+ { cursor: 'cursor', limit: 1 },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Courier.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('archive: only required params', async () => {
+ const responsePromise = client.journeys.templates.archive('x', { templateId: 'x' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('archive: required and optional params', async () => {
+ const response = await client.journeys.templates.archive('x', { templateId: 'x' });
+ });
+
+ // Mock server tests are disabled
+ test.skip('listVersions: only required params', async () => {
+ const responsePromise = client.journeys.templates.listVersions('x', { templateId: 'x' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('listVersions: required and optional params', async () => {
+ const response = await client.journeys.templates.listVersions('x', { templateId: 'x' });
+ });
+
+ // Mock server tests are disabled
+ test.skip('publish: only required params', async () => {
+ const responsePromise = client.journeys.templates.publish('x', { templateId: 'x' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('publish: required and optional params', async () => {
+ const response = await client.journeys.templates.publish('x', {
+ templateId: 'x',
+ version: 'v321669910225',
+ });
+ });
+
+ // Mock server tests are disabled
+ test.skip('replace: only required params', async () => {
+ const responsePromise = client.journeys.templates.replace('x', {
+ templateId: 'x',
+ notification: {
+ brand: { id: 'id' },
+ content: { elements: [{}], version: '2022-01-01' },
+ name: 'name',
+ subscription: { topic_id: 'topic_id' },
+ tags: ['string'],
+ },
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('replace: required and optional params', async () => {
+ const response = await client.journeys.templates.replace('x', {
+ templateId: 'x',
+ notification: {
+ brand: { id: 'id' },
+ content: {
+ elements: [
+ {
+ channels: ['string'],
+ if: 'if',
+ loop: 'loop',
+ ref: 'ref',
+ type: 'text',
+ },
+ ],
+ version: '2022-01-01',
+ scope: 'default',
+ },
+ name: 'name',
+ subscription: { topic_id: 'topic_id' },
+ tags: ['string'],
+ },
+ state: 'state',
+ });
+ });
+});
diff --git a/tests/api-resources/tenants/templates/templates.test.ts b/tests/api-resources/tenants/templates/templates.test.ts
index 94e7ae8e..2230eb3f 100644
--- a/tests/api-resources/tenants/templates/templates.test.ts
+++ b/tests/api-resources/tenants/templates/templates.test.ts
@@ -49,6 +49,23 @@ describe('resource templates', () => {
).rejects.toThrow(Courier.NotFoundError);
});
+ // Mock server tests are disabled
+ test.skip('delete: only required params', async () => {
+ const responsePromise = client.tenants.templates.delete('template_id', { tenant_id: 'tenant_id' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('delete: required and optional params', async () => {
+ const response = await client.tenants.templates.delete('template_id', { tenant_id: 'tenant_id' });
+ });
+
// Mock server tests are disabled
test.skip('publish: only required params', async () => {
const responsePromise = client.tenants.templates.publish('template_id', { tenant_id: 'tenant_id' });
diff --git a/yarn.lock b/yarn.lock
index f6eae3cd..18e7cbdc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -709,11 +709,6 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@pkgr/core@^0.2.4":
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c"
- integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==
-
"@sinclair/typebox@^0.27.8":
version "0.27.8"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
@@ -1515,14 +1510,6 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-eslint-plugin-prettier@^5.4.1:
- version "5.4.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af"
- integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==
- dependencies:
- prettier-linter-helpers "^1.0.0"
- synckit "^0.11.7"
-
eslint-plugin-unused-imports@^4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738"
@@ -1674,11 +1661,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-diff@^1.1.2:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
- integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
-
fast-glob@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
@@ -2841,13 +2823,6 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-prettier-linter-helpers@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
- integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
- dependencies:
- fast-diff "^1.1.2"
-
prettier@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848"
@@ -3144,13 +3119,6 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-synckit@^0.11.7:
- version "0.11.8"
- resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457"
- integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==
- dependencies:
- "@pkgr/core" "^0.2.4"
-
test-exclude@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"