From 6a733ae31150b615d9361bec237ddad9ce6291b8 Mon Sep 17 00:00:00 2001 From: Chris Bell Date: Mon, 23 Feb 2026 23:23:00 -0500 Subject: [PATCH 01/96] Update Agent Toolkit tools reference to match current implementation (#1319) - Add getEmailLayout tool to email layouts section - Add getMessage, getMessageDeliveryLogs, and getMessageEvents tools to messages section - Remove listUsers (does not exist in agent-toolkit) - Fix 'enviroinment' typo in commits section - Fix 'Email Layouts' header to use sentence case ('Email layouts') - Reorder items within sections to match source code export order Co-authored-by: Cursor Agent --- .../agent-toolkit/tools-reference.mdx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/content/developer-tools/agent-toolkit/tools-reference.mdx b/content/developer-tools/agent-toolkit/tools-reference.mdx index 8fbacb990..4189f7a74 100644 --- a/content/developer-tools/agent-toolkit/tools-reference.mdx +++ b/content/developer-tools/agent-toolkit/tools-reference.mdx @@ -4,7 +4,7 @@ description: Learn more about the tools available in the Knock Agent Toolkit. section: Developer tools --- -The Knock Agent Toolkit exposes a suite of tools that your AI Agents can invoke to power cross-channel user messaging, without any integration logic. You can find the full list of available tools below. +The Knock Agent Toolkit exposes a suite of tools that your AI agents can invoke to power cross-channel user messaging, without any integration logic. You can find the full list of available tools below. ## Channels (`channels`) @@ -13,16 +13,17 @@ The Knock Agent Toolkit exposes a suite of tools that your AI Agents can invoke ## Commits (`commits`) - `listCommits`: List all commits in a single environment -- `commitAllChanges`: Commit all changes in an enviroinment +- `commitAllChanges`: Commit all changes in an environment - `promoteAllCommits`: Promote all commits from one environment to another ## Documentation (`documentation`) - `searchDocumentation`: Perform a search of the Knock documentation -## Email Layouts (`emailLayouts`) +## Email layouts (`emailLayouts`) - `listEmailLayouts`: List all email layouts in an environment +- `getEmailLayout`: Get an email layout by its key - `createOrUpdateEmailLayout`: Create or update an email layout in an environment ## Environments (`environments`) @@ -42,13 +43,16 @@ The Knock Agent Toolkit exposes a suite of tools that your AI Agents can invoke ## Messages (`messages`) +- `getMessage`: Get a message by its ID - `getMessageContent`: Get the content of a sent message +- `getMessageDeliveryLogs`: Get the delivery logs for a message +- `getMessageEvents`: Get the event timeline for a message ## Objects (`objects`) - `listObjects`: List all objects in a collection in an environment -- `createOrUpdateObject`: Create or update an object in a collection - `getObject`: Get an object in a collection by its id +- `createOrUpdateObject`: Create or update an object in a collection - `subscribeUsersToObject`: Subscribe one or more users to an object in a collection - `unsubscribeUsersFromObject`: Unsubscribe one or more users from an object in a collection @@ -61,14 +65,13 @@ The Knock Agent Toolkit exposes a suite of tools that your AI Agents can invoke ## Tenants (`tenants`) - `listTenants`: List all tenants in an environment -- `createOrUpdateTenant`: Create or update a tenant in an environment - `getTenant`: Get a tenant by its key +- `createOrUpdateTenant`: Create or update a tenant in an environment ## Users (`users`) -- `listUsers`: List all users in an environment -- `createOrUpdateUser`: Create or update a user in an environment - `getUser`: Get a user by their id +- `createOrUpdateUser`: Create or update a user in an environment - `getUserPreferences`: Get the preferences for a user - `setUserPreferences`: Set the preferences for a user - `getUserMessages`: Get the messages for a user From a68391208abde73954fa53a89373380086b47aeb Mon Sep 17 00:00:00 2001 From: Chris Bell Date: Tue, 24 Feb 2026 12:22:56 -0500 Subject: [PATCH 02/96] chore: rework docs for remote mcp server (#1323) * chore: rework docs for remote mcp server * Add Claude Code install instructions to MCP server docs Co-authored-by: Chris Bell --------- Co-authored-by: Cursor Agent --- content/developer-tools/mcp-server.mdx | 143 ++++++++----------------- 1 file changed, 46 insertions(+), 97 deletions(-) diff --git a/content/developer-tools/mcp-server.mdx b/content/developer-tools/mcp-server.mdx index 43227da52..9c7b4a69d 100644 --- a/content/developer-tools/mcp-server.mdx +++ b/content/developer-tools/mcp-server.mdx @@ -16,7 +16,7 @@ section: Developer tools } /> -Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the Model Context Protocol (MCP) so that your AI agents can discover and use Knock via tool calling. +Knock ships a remote MCP server at `mcp.knock.app/mcp` that exposes the primitives of Knock to LLMs and AI via the Model Context Protocol (MCP) so that your AI agents can discover and use Knock via tool calling. Here are some examples of how you can use the MCP server in your workflow: @@ -26,57 +26,31 @@ Here are some examples of how you can use the MCP server in your workflow: ## Get started -To get started with the MCP server, you'll need to create a [service token](/developer-tools/service-tokens) to use to authenticate against your Knock account. You can do so on the **Service tokens** page under the **Account** section of your account settings in the Knock dashboard. +The Knock MCP server is a remote server—no local installation or Node.js setup is required. You connect to `https://mcp.knock.app/mcp` directly from your MCP client and authenticate using your Knock account via OAuth. This means your Knock credentials are managed securely through the standard sign-in flow rather than requiring a service token. -Once you have your service, you can then setup the MCP Server in any MCP Client-compatible AI application. We've added the setup instructions below for both Cursor and Claude Desktop, but the same instructions apply to any other MCP Client-compatible application. +We've added setup instructions below for Cursor, Claude Desktop, and Claude Code, but the same instructions apply to any other MCP client-compatible application. - - Note: To run the local MCP server you must have Node 20 - or higher installed and accessible globally on your system. You can test - this by running `node --version` in your terminal. You can download Node - from{" "} - - the official site - - . - - } -/> ### Cursor -Click this button to add the Knock MCP server to Cursor (version 1.0 or higher is required). - -
- [![Install MCP - Server](/images/mcp-server/mcp-install-dark.svg)](cursor://anysphere.cursor-deeplink/mcp/install?name=knock&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBrbm9ja2xhYnMvYWdlbnQtdG9vbGtpdCIsIi1wIiwibG9jYWwtbWNwIiwiLS1zZXJ2aWNlLXRva2VuIiwiWU9VUi1TRVJWSUNFLVRPS0VOIl0sIm5hbWUiOiJLbm9jayBNQ1AgU2VydmVyIn0=>) -
- -#### Manual installation - 1. Go to **Settings** > **Cursor Settings** and find the "Tools & Integrations" section. 2. Click "New MCP server" under **MCP Tools**. -3. Inside of your `mcp.json` file under the `mcpServers` key, add the following: +3. Inside your `mcp.json` file under the `mcpServers` key, add the following: ```json { "knock": { - "command": "npx", - "args": ["-y", "@knocklabs/agent-toolkit", "-p", "local-mcp"], - "name": "Knock MCP Server", - "env": { - "KNOCK_SERVICE_TOKEN": "YOUR-SERVICE-TOKEN" - } + "url": "https://mcp.knock.app/mcp", + "name": "Knock MCP Server" } } ``` +4. When Cursor prompts you to authenticate, sign in with your Knock account. + ### Claude Desktop 1. Open the Claude Desktop settings and find the "Developer" section. -2. Click to "Edit Config." +2. Click "Edit Config." 3. Open your `claude_desktop_config.json` file in your preferred text editor. 4. Add the following contents to the file (or add to the `mcpServers` section if it exists): @@ -84,65 +58,35 @@ Click this button to add the Knock MCP server to Cursor (version 1.0 or higher i { "mcpServers": { "knock": { - "command": "npx", - "args": ["-y", "@knocklabs/agent-toolkit", "-p", "local-mcp"], - "env": { - "KNOCK_SERVICE_TOKEN": "YOUR-SERVICE-TOKEN" - } + "url": "https://mcp.knock.app/mcp" } } } ``` -## Configuring the available tools - -It's not recommended to expose all tools that the Knock MCP server has to the LLM. Instead, you should expose only the tools that are required to complete the task at hand. You can configure the available tools by passing in the `--tools` flag when starting the MCP server. +5. Restart Claude Desktop. When you first use a Knock tool, you'll be prompted to sign in with your Knock account. -The `--tools` flag accepts a list of tools, where the tools are referenced in a `category.tool` format. For example, to expose all user tools, you would pass `--tools users.*`. To expose all workflow tools, you would pass `--tools workflows.*`. +### Claude Code -The name of the tool is the name of the tool as it appears in the [tools reference](/developer-tools/agent-toolkit/tools-reference), which will be a camel-cased version like `createOrUpdateUser` or `listEnvironments`. +1. Run the following command to add the Knock MCP server: -Here are some examples of how you can configure the available tools: - -- Expose all tools: `--tools *` -- Expose all `users` tools: `--tools users.*` -- Expose only the `createOrUpdateUser` tool: `--tools users.createOrUpdateUser` -- Expose all `users` and `workflows` tools: `--tools users.* workflows.*` - -Here's a full example of how you pass tool configurations to the MCP server in Cursor: - -```json title="mcp-with-tools.json" -{ - "knock": { - "command": "npx", - "args": [ - "-y", - "@knocklabs/agent-toolkit", - "-p", - "local-mcp", - "--tools", - "users.createOrUpdateUser", - "workflows.*" - ], - "name": "Knock MCP Server", - "env": { - "KNOCK_SERVICE_TOKEN": "YOUR-SERVICE-TOKEN" - } - } -} +```bash +claude mcp add --transport http knock https://mcp.knock.app/mcp ``` -## Workflows-as-tools - -The Knock MCP server also supports exposing your workflows as individual tools. This allows you to provide a specific and precise interface to the LLM for invoking workflow triggers, including describing the data trigger requirements for your workflows. +2. Start Claude Code and run `/mcp` to authenticate with your Knock account. -By default, the MCP server will **not** expose any workflows-as-tools. To opt into this behavior, you can pass in the `--workflows` flag when starting the MCP server. +## Tool groups -By default, passing the `--workflows` flag will expose **all** workflows in your Knock account as tools. If you want to control the exact workflows that are exposed as tools, you can pass a list of workflow keys to the `--workflows` flag. For example: +When connecting to the Knock MCP server, you can choose exactly which groups of tools to enable. Limiting the active tool groups to only what you need keeps the tool list manageable and reduces the risk of unintended changes. -```bash title="Passing a list of workflow keys" ---workflows workflow-key-1 workflow-key-2 -``` +| Group | Description | +| -------------------- | --------------------------------------------------------------------------------------------------------------- | +| **Manage resources** | Create and manage notification workflows, channels, templates, email layouts, partials, and other configuration | +| **Commits** | Commit and promote changes across environments | +| **Debug** | Inspect environments and view sent message logs | +| **Manage data** | Manage users, tenants, and object data | +| **Documentation** | Search Knock documentation | ## What tools are available? @@ -161,6 +105,12 @@ The Knock MCP server exposes a full suite of tools for creating and managing wor Using these tools you can create a complex prompt that describes one or more workflows that you'd like to create with natural language. +## Workflows-as-tools + +The Knock MCP server also supports exposing your workflows as individual tools. This gives the LLM a specific and precise interface for invoking workflow triggers, including describing the data trigger requirements for your workflows. + +By default, the MCP server will **not** expose any workflows as tools. To opt into this behavior, contact us or refer to your MCP client's tool configuration options. + ## Related links - [Building with LLMs](/developer-tools/building-with-llms) @@ -169,23 +119,22 @@ Using these tools you can create a complex prompt that describes one or more wor ## Frequently asked questions - - No, currently we support a local MCP server only. We are working - on a remote MCP server so that an individual Knock account can be - authenticated. - - - Some MCP clients will warn you about having more than 50 tools. By default, Knock ships with 30 tools, but when using workflows-as-tools, this number can grow quickly. - - To address this, you should opt into only using the tools you need. For - example, if you only use the `users.create` tool, you can expose only that - tool by passing in the `--tools` flag. - - - - The local MCP server requires Node 20 or higher and Claude may be defaulting to an older Node version if you have multiple versions installed. Try uninstalling older versions of Node and then restarting Claude to resolve the issue. + + Some MCP clients will warn you about having more than 50 tools. To address + this, enable only the tool groups you need for the task at hand. For + example, if you're only managing user data, enable the **Manage data** group + and leave the others disabled. - If you see an error like _"The model returned an error. Try disabling MCP servers, or switch models,"_ check which model is selected for the Cursor agent. Make sure it's explicitly set to a supported model like `claude-4-sonnet` rather than relying on automatic model selection. + If you see an error like _"The model returned an error. Try disabling MCP + servers, or switch models,"_ check which model is selected for the Cursor + agent. Make sure it's explicitly set to a supported model like + `claude-sonnet-4` rather than relying on automatic model selection. + + + The remote MCP server at `mcp.knock.app/mcp` uses OAuth-based authentication + and requires signing in with your Knock account. If you need service + token-based authentication for a self-hosted or CI environment, please + contact us. From a752b31a16655490d9c41362e422a3216b201015 Mon Sep 17 00:00:00 2001 From: knock-eng-bot <133689285+knock-eng-bot@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:22:08 +0100 Subject: [PATCH 03/96] chore: update control openapi spec (#1288) * chore: update control openapi spec to v0.1.1191 * chore: update control openapi spec to v0.1.1192 * chore: update control openapi spec to v0.1.1193 * chore: update control openapi spec to v0.1.1196 * chore: update control openapi spec to v0.1.1199 * chore: update control openapi spec to v0.1.1204 * chore: update control openapi spec to v0.1.1207 * chore: update control openapi spec to v0.1.1227 * chore: update control openapi spec to v0.1.1231 * chore: update control openapi spec to v0.1.1233 * chore: update control openapi spec to v0.1.1236 * chore: update control openapi spec to v0.1.1237 * chore: manually update stainless spec * chore: update control openapi spec to v0.1.1238 * chore: add members to customizations --------- Co-authored-by: Chris Bell --- data/specs/mapi/customizations.yml | 4 + data/specs/mapi/openapi.yml | 4155 +++++++++++++++++++--------- data/specs/mapi/stainless.yml | 22 +- 3 files changed, 2937 insertions(+), 1244 deletions(-) diff --git a/data/specs/mapi/customizations.yml b/data/specs/mapi/customizations.yml index 93d73cf0c..e111c9284 100644 --- a/data/specs/mapi/customizations.yml +++ b/data/specs/mapi/customizations.yml @@ -84,3 +84,7 @@ resources: name: Authentication description: |- Authentication methods for the Knock management API. + members: + name: Members + description: |- + Members are the users who have access to the Knock account. diff --git a/data/specs/mapi/openapi.yml b/data/specs/mapi/openapi.yml index 5801e9102..e66aefba4 100644 --- a/data/specs/mapi/openapi.yml +++ b/data/specs/mapi/openapi.yml @@ -1,6 +1,35 @@ components: responses: {} schemas: + RequestTemplateQueryParamsArray: + description: A list of key-value pairs for the request query params. Each object should contain key and value fields with string values. + example: + - key: key + value: value + items: + properties: + key: + description: The key of the query param. + example: key + type: string + x-struct: null + x-validate: null + value: + description: The value of the query param. + example: value + type: string + x-struct: null + x-validate: null + required: + - key + - value + type: object + x-struct: null + x-validate: null + title: RequestTemplateQueryParamsArray + type: array + x-struct: null + x-validate: null SmsChannelSettings: description: SMS channel settings. Only used as configuration as part of a workflow channel step. example: @@ -46,8 +75,13 @@ components: - $ref: '#/components/schemas/WorkflowDelayStep' - $ref: '#/components/schemas/WorkflowBatchStep' - $ref: '#/components/schemas/WorkflowFetchStep' + - $ref: '#/components/schemas/WorkflowUpdateDataStep' + - $ref: '#/components/schemas/WorkflowUpdateObjectStep' + - $ref: '#/components/schemas/WorkflowUpdateTenantStep' + - $ref: '#/components/schemas/WorkflowUpdateUserStep' - $ref: '#/components/schemas/WorkflowThrottleStep' - $ref: '#/components/schemas/WorkflowBranchStep' + - $ref: '#/components/schemas/WorkflowRandomCohortStep' - $ref: '#/components/schemas/WorkflowTriggerWorkflowStep' description: A step within a workflow. Each workflow step, regardless of its type, share a common set of core attributes (`type`, `ref`, `name`, `description`, `conditions`). example: @@ -71,6 +105,13 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.WorkflowStep x-validate: null + RequestTemplateQueryParamsString: + description: A template string that should resolve to a JSON object representing the query params. + example: '{{ data.request_query_params }}' + title: RequestTemplateQueryParamsString + type: string + x-struct: null + x-validate: null EmailImageBlock: description: An image block in an email template. example: @@ -217,6 +258,79 @@ components: type: object x-struct: null x-validate: null + ChannelGroupRuleRequest: + description: A rule that determines if a channel should be executed as part of a channel group. + example: + channel_key: email-channel + index: 0 + rule_type: always + properties: + argument: + description: For conditional rules, the value to compare against. + nullable: true + type: string + x-struct: null + x-validate: null + channel_key: + description: The key of the channel this rule applies to. + type: string + x-struct: null + x-validate: null + index: + description: The order index of this rule within the channel group. + type: integer + x-struct: null + x-validate: null + operator: + description: For conditional rules, the operator to apply. + enum: + - equal_to + - not_equal_to + - greater_than + - less_than + - greater_than_or_equal_to + - less_than_or_equal_to + - contains + - not_contains + - contains_all + - not_contains_all + - is_timestamp_before + - is_timestamp_on_or_after + - is_timestamp_between + - empty + - not_empty + - exists + - not_exists + - is_timestamp + - is_audience_member + - is_not_audience_member + example: equal_to + nullable: true + type: string + x-struct: null + x-validate: null + rule_type: + description: The type of rule (if = conditional, unless = negative conditional, always = always apply). + enum: + - if + - unless + - always + type: string + x-struct: null + x-validate: null + variable: + description: For conditional rules, the variable to evaluate. + nullable: true + type: string + x-struct: null + x-validate: null + required: + - channel_key + - rule_type + title: ChannelGroupRuleRequest + type: object + x-struct: Elixir.ControlWeb.V1.Specs.ChannelGroupRuleRequest + x-validate: null PreviewWorkflowTemplateResponse: description: A response to a preview workflow template request. example: @@ -269,6 +383,102 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.PreviewWorkflowTemplateResponse x-validate: null + RequestTemplateHeadersString: + description: A template string that should resolve to a JSON object representing the headers. + example: '{{ data.request_headers }}' + title: RequestTemplateHeadersString + type: string + x-struct: null + x-validate: null + WorkflowUpdateTenantStep: + description: An update tenant step. Updates properties of a specific tenant referenced in the workflow. + example: + description: Update tenant step description. + name: Update tenant + ref: update_tenant_1 + settings: + recipient_gid: gid://Object/$tenants/tenant-123 + recipient_mode: reference + update_properties: '{"name": "Updated Tenant"}' + type: update_tenant + properties: + conditions: + anyOf: + - $ref: '#/components/schemas/ConditionGroup' + - nullable: true + x-struct: null + x-validate: null + description: A conditions object that describes one or more conditions to be met in order for the step to be executed. + type: object + x-struct: null + x-validate: null + description: + description: An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. + example: Update tenant step description. + nullable: true + type: string + x-struct: null + x-validate: null + name: + description: A name for the workflow step. + example: Update tenant + nullable: true + type: string + x-struct: null + x-validate: null + ref: + description: The reference key of the workflow step. Must be unique per workflow. + example: update_tenant_1 + type: string + x-struct: null + x-validate: null + settings: + description: The settings for the update tenant step. + properties: + recipient_gid: + description: 'The global identifier (GID) of the tenant to update. Required when recipient_mode is ''reference''. Format: gid://Object/$tenants/{id}' + example: gid://Object/$tenants/tenant-123 + nullable: true + type: string + x-struct: null + x-validate: null + recipient_mode: + description: The recipient mode determining how the tenant is selected. 'current' uses the workflow's current tenant. 'reference' uses a specific tenant ID. + enum: + - current + - reference + example: reference + type: string + x-struct: null + x-validate: null + update_properties: + description: A JSON string or Liquid template that evaluates to the properties to update on the tenant. + example: '{"name": "Updated Tenant", "status": "active"}' + type: string + x-struct: null + x-validate: null + required: + - recipient_mode + - update_properties + type: object + x-struct: null + x-validate: null + type: + description: The type of the workflow step. + enum: + - update_tenant + example: update_tenant + type: string + x-struct: null + x-validate: null + required: + - type + - ref + - settings + title: WorkflowUpdateTenantStep + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowUpdateTenantStep + x-validate: null WorkflowDelayStep: description: A delay function step. Read more in the [docs](https://docs.knock.app/designing-workflows/delay-function). example: @@ -372,13 +582,20 @@ components: x-validate: null headers: description: The headers of the request. Can be a template string or a list of key-value pairs. + example: + - key: X-API-Key + value: "1234567890" oneOf: - description: A template string that should resolve to a JSON object representing the headers. example: '{{ data.request_headers }}' + title: RequestTemplateHeadersString type: string x-struct: null x-validate: null - description: A list of key-value pairs for the request headers. Each object should contain key and value fields with string values. + example: + - key: X-API-Key + value: "1234567890" items: properties: key: @@ -399,9 +616,11 @@ components: type: object x-struct: null x-validate: null + title: RequestTemplateHeadersArray type: array x-struct: null x-validate: null + title: RequestTemplateHeaders type: object x-struct: null x-validate: null @@ -419,13 +638,20 @@ components: x-validate: null query_params: description: The query params of the request. Can be a template string or a list of key-value pairs. + example: + - key: key + value: value oneOf: - description: A template string that should resolve to a JSON object representing the query params. example: '{{ data.request_query_params }}' + title: RequestTemplateQueryParamsString type: string x-struct: null x-validate: null - description: A list of key-value pairs for the request query params. Each object should contain key and value fields with string values. + example: + - key: key + value: value items: properties: key: @@ -446,9 +672,11 @@ components: type: object x-struct: null x-validate: null + title: RequestTemplateQueryParamsArray type: array x-struct: null x-validate: null + title: RequestTemplateQueryParams type: object x-struct: null x-validate: null @@ -727,8 +955,19 @@ components: example: partial: content:

Hello, world!

+ description: This is a test partial + input_schema: + - key: text_field + label: My text field + settings: + description: A description of the text field + max_length: 100 + min_length: 10 + required: true + type: text name: My Partial type: html + visual_block_enabled: true properties: partial: $ref: '#/components/schemas/PartialRequest' @@ -841,7 +1080,8 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true type: string x-struct: null x-validate: null @@ -869,6 +1109,12 @@ components: type: array x-struct: null x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true + type: string + x-struct: null + x-validate: null required: description: Whether the field is required. example: true @@ -929,7 +1175,14 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true type: string x-struct: null x-validate: null @@ -1220,7 +1473,14 @@ components: description: Settings for the button field. properties: description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true type: string x-struct: null x-validate: null @@ -1528,6 +1788,7 @@ components: label: Image Action settings: description: A link to open when the paywall image is clicked + placeholder: A placeholder for the image action required: true type: text alt: @@ -1535,6 +1796,7 @@ components: label: Alt Text settings: description: A description of the paywall image + placeholder: A placeholder for the alt text required: true type: text key: image_field @@ -1548,6 +1810,7 @@ components: label: Image URL settings: description: The URL of the paywall image + placeholder: A placeholder for the image URL required: true type: url properties: @@ -1572,7 +1835,14 @@ components: description: Settings for the image field. properties: description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true type: string x-struct: null x-validate: null @@ -1628,6 +1898,7 @@ components: - $ref: '#/components/schemas/MessageTypeBooleanField' - $ref: '#/components/schemas/MessageTypeButtonField' - $ref: '#/components/schemas/MessageTypeImageField' + - $ref: '#/components/schemas/MessageTypeJsonField' - $ref: '#/components/schemas/MessageTypeMarkdownField' - $ref: '#/components/schemas/MessageTypeMultiSelectField' - $ref: '#/components/schemas/MessageTypeSelectField' @@ -1719,37 +1990,101 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.EmailLayoutRequest x-validate: null + WrappedChannelGroupResponse: + description: Wraps the ChannelGroup response under the `channel_group` key. + example: + channel_group: + channel_rules: + - channel: + archived_at: null + created_at: "2021-01-01T00:00:00Z" + custom_icon_url: null + id: 01234567-89ab-cdef-0123-456789abcdef + key: my-sendgrid-channel + name: My Sendgrid Channel + provider: sendgrid + type: email + updated_at: "2021-01-01T00:00:00Z" + created_at: "2021-01-01T00:00:00Z" + index: 0 + rule_type: always + updated_at: "2021-01-01T00:00:00Z" + channel_type: push + created_at: "2021-01-01T00:00:00Z" + key: push-group + name: Push Notification Group + operator: any + source: user + updated_at: "2021-01-01T00:00:00Z" + properties: + channel_group: + $ref: '#/components/schemas/ChannelGroup' + required: + - channel_group + title: WrappedChannelGroupResponse + type: object + x-struct: null + x-validate: null PartialRequest: description: A partial object with attributes to update or create a partial. example: content:

Hello, world!

+ description: This is a test partial + input_schema: + - key: text_field + label: My text field + settings: + description: A description of the text field + max_length: 100 + min_length: 10 + required: true + type: text name: My Partial type: html + visual_block_enabled: true properties: content: - description: The content of the partial. + description: The partial content. type: string x-struct: null x-validate: null description: - description: The description of the partial. - nullable: true + description: An arbitrary string attached to a partial object. Useful for adding notes about the partial for internal purposes. Maximum of 280 characters allowed. type: string x-struct: null x-validate: null icon_name: - description: The name of the icon to be used in the visual editor. Only relevant when `visual_block_enabled` is `true`. - nullable: true + description: The name of the icon to be used in the visual editor. type: string x-struct: null x-validate: null + input_schema: + description: The field types available for the partial. + items: + anyOf: + - $ref: '#/components/schemas/MessageTypeBooleanField' + - $ref: '#/components/schemas/MessageTypeButtonField' + - $ref: '#/components/schemas/MessageTypeImageField' + - $ref: '#/components/schemas/MessageTypeJsonField' + - $ref: '#/components/schemas/MessageTypeMarkdownField' + - $ref: '#/components/schemas/MessageTypeMultiSelectField' + - $ref: '#/components/schemas/MessageTypeSelectField' + - $ref: '#/components/schemas/MessageTypeTextField' + - $ref: '#/components/schemas/MessageTypeTextareaField' + - $ref: '#/components/schemas/MessageTypeUrlField' + type: object + x-struct: null + x-validate: null + type: array + x-struct: null + x-validate: null name: - description: The name of the partial. + description: A name for the partial. Must be at maximum 255 characters in length. type: string x-struct: null x-validate: null type: - description: The type of the partial. + description: The partial type. One of 'html', 'json', 'markdown', 'text'. enum: - html - text @@ -1760,8 +2095,6 @@ components: x-validate: null visual_block_enabled: description: Indicates whether the partial can be used in the visual editor. Only applies to HTML partials. - example: false - nullable: true type: boolean x-struct: null x-validate: null @@ -1787,30 +2120,120 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.ConditionGroup x-validate: null - BroadcastRequest: - description: A broadcast request for upserting a broadcast. + MessageTypeJsonField: + description: A JSON field used in a message type. example: - categories: - - announcement - description: A broadcast to all users - name: My Broadcast + key: json_field + label: JSON Field settings: - is_commercial: true - override_preferences: false - steps: - - channel_key: in-app-feed - name: Channel 1 - ref: channel_1 - template: - action_url: '{{ vars.app_url }}' - markdown_body: Hello **{{ recipient.name }}** - type: channel - target_audience_key: all-users - properties: - categories: - description: A list of categories that the broadcast belongs to. - items: - type: string + default: + key: value + description: A description of the JSON field + placeholder: A placeholder for the JSON field + required: true + schema: + properties: + key: + type: string + required: + - key + type: json + properties: + key: + description: The unique key of the field. + example: key + type: string + x-struct: null + x-validate: null + label: + description: The label of the field. + example: Label + nullable: true + type: string + x-struct: null + x-validate: null + settings: + description: Settings for the json field. + properties: + default: + description: The default value of the JSON field. + example: + key: value + nullable: true + type: object + x-struct: null + x-validate: null + description: + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true + type: string + x-struct: null + x-validate: null + required: + description: Whether the field is required. + example: true + type: boolean + x-struct: null + x-validate: null + schema: + description: A JSON schema used to validate the structure of the JSON provided. Must be a valid JSON schema. + example: + properties: + key: + type: string + nullable: true + type: object + x-struct: null + x-validate: null + type: object + x-struct: null + x-validate: null + type: + description: The type of the field. + enum: + - json + example: json + type: string + x-struct: null + x-validate: null + required: + - type + - key + - label + title: MessageTypeJsonField + type: object + x-struct: Elixir.ControlWeb.V1.Specs.MessageTypes.JsonField + x-validate: null + BroadcastRequest: + description: A broadcast request for upserting a broadcast. + example: + categories: + - announcement + description: A broadcast to all users + name: My Broadcast + settings: + is_commercial: true + override_preferences: false + steps: + - channel_key: in-app-feed + name: Channel 1 + ref: channel_1 + template: + action_url: '{{ vars.app_url }}' + markdown_body: Hello **{{ recipient.name }}** + type: channel + target_audience_key: all-users + properties: + categories: + description: A list of categories that the broadcast belongs to. + items: + type: string x-struct: null x-validate: null type: array @@ -1863,6 +2286,7 @@ components: - $ref: '#/components/schemas/WorkflowEmailStep' - $ref: '#/components/schemas/WorkflowBranchStep' - $ref: '#/components/schemas/WorkflowDelayStep' + - $ref: '#/components/schemas/WorkflowRandomCohortStep' description: A step within a broadcast. Each step, regardless of its type, share a common set of core attributes (`type`, `ref`, `name`, `description`, `conditions`). type: object x-struct: null @@ -2520,6 +2944,7 @@ components: description: A description of the text field max_length: 100 min_length: 10 + placeholder: A placeholder for the text field required: true type: text properties: @@ -2547,7 +2972,8 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true type: string x-struct: null x-validate: null @@ -2561,6 +2987,12 @@ components: type: integer x-struct: null x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true + type: string + x-struct: null + x-validate: null required: description: Whether the field is required. example: true @@ -2863,6 +3295,73 @@ components: type: object x-struct: null x-validate: null + WorkflowRandomCohortStep: + description: An experiment step. Deterministically assigns recipients to percentage-based cohorts for A/B testing and experimentation. + example: + cohort_branches: + - name: Control + percentage: "50" + steps: [] + terminates: false + - name: Variant + percentage: "50" + steps: [] + terminates: false + description: Experiment step description. + name: Experiment + ref: experiment_1 + type: random_cohort + properties: + cohort_branches: + description: A list of cohort branches. Must have between 2 and 10 branches, and percentages must sum to 100. + items: + $ref: '#/components/schemas/WorkflowRandomCohortStepBranch' + type: array + x-struct: null + x-validate: null + cohort_key: + description: The key used to deterministically assign recipients to cohorts. Defaults to the recipient ID if not provided. + example: tenant.id + nullable: true + type: string + x-struct: null + x-validate: null + description: + description: An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. + example: Experiment step description. + nullable: true + type: string + x-struct: null + x-validate: null + name: + description: A name for the workflow step. + example: Experiment + nullable: true + type: string + x-struct: null + x-validate: null + ref: + description: The reference key of the workflow step. Must be unique per workflow. + example: experiment_1 + type: string + x-struct: null + x-validate: null + type: + description: The type of step. + enum: + - random_cohort + example: random_cohort + type: string + x-struct: null + x-validate: null + required: + - type + - ref + - cohort_branches + title: WorkflowRandomCohortStep + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowRandomCohortStep + x-validate: null WorkflowThrottleStep: description: A throttle function step. Read more in the [docs](https://docs.knock.app/designing-workflows/throttle-function). example: @@ -3346,6 +3845,58 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.WhoamiResponse x-validate: null + ChannelGroupRequest: + description: A request to create or update a channel group. + example: + channel_rules: + - channel_key: push-fcm + index: 0 + rule_type: always + channel_type: push + name: Push Notification Group + operator: any + properties: + channel_rules: + description: Rules for determining which channels should be used. + items: + $ref: '#/components/schemas/ChannelGroupRuleRequest' + type: array + x-struct: null + x-validate: null + channel_type: + description: The type of channels contained in this group. + enum: + - email + - in_app + - in_app_feed + - in_app_guide + - sms + - push + - chat + - http + type: string + x-struct: null + x-validate: null + name: + description: The human-readable name of the channel group. + type: string + x-struct: null + x-validate: null + operator: + description: Determines how the channel rules are applied ('any' means any rule can match, 'all' means all rules must match). + enum: + - any + - all + type: string + x-struct: null + x-validate: null + required: + - name + - channel_type + title: ChannelGroupRequest + type: object + x-struct: Elixir.ControlWeb.V1.Specs.ChannelGroupRequest + x-validate: null MessageTypeUrlField: description: A URL field used in a message type. example: @@ -3353,6 +3904,7 @@ components: label: URL Field settings: description: A description of the URL field + placeholder: A placeholder for the URL field required: true type: url properties: @@ -3380,7 +3932,14 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true type: string x-struct: null x-validate: null @@ -3471,15 +4030,45 @@ components: type: object x-struct: null x-validate: null + RequestTemplateHeadersArray: + description: A list of key-value pairs for the request headers. Each object should contain key and value fields with string values. + example: + - key: X-API-Key + value: "1234567890" + items: + properties: + key: + description: The key of the header. + example: X-API-Key + type: string + x-struct: null + x-validate: null + value: + description: The value of the header. + example: "1234567890" + type: string + x-struct: null + x-validate: null + required: + - key + - value + type: object + x-struct: null + x-validate: null + title: RequestTemplateHeadersArray + type: array + x-struct: null + x-validate: null GuideActivationUrlPattern: - description: A rule that controls when a guide should be shown based on the user's location in the application. + description: A rule that controls when a guide should be shown based on the user's location in the application. At least one of `pathname` or `search` must be provided. example: directive: allow pathname: /dashboard/* + search: tab=settings properties: directive: default: allow - description: Whether to allow or block the guide at the specified pathname. + description: Whether to allow or block the guide at the specified location. enum: - allow - block @@ -3492,9 +4081,14 @@ components: type: string x-struct: null x-validate: null + search: + description: The URL query string pattern to match against (without the leading '?'). Supports URLPattern API syntax. + example: tab=settings&* + type: string + x-struct: null + x-validate: null required: - directive - - pathname title: GuideActivationUrlPattern type: object x-struct: Elixir.ControlWeb.V1.Specs.GuideActivationUrlPattern @@ -3746,6 +4340,63 @@ components: type: object x-struct: null x-validate: null + Member: + description: A member of the account. + example: + created_at: "2024-01-15T10:30:00Z" + id: d4b8e8e0-1234-5678-9abc-def012345678 + role: admin + updated_at: "2024-06-20T14:45:00Z" + user: + avatar_url: https://www.gravatar.com/avatar/abc123 + created_at: "2024-01-10T08:00:00Z" + email: jane@example.com + id: a1b2c3d4-5678-9abc-def0-123456789abc + name: Jane Doe + updated_at: "2024-06-18T12:00:00Z" + properties: + created_at: + description: The timestamp of when the member joined the account. + format: date-time + type: string + x-struct: null + x-validate: null + id: + description: The unique identifier of the member. + format: uuid + type: string + x-struct: null + x-validate: null + role: + description: The member's role in the account. + enum: + - owner + - admin + - member + - production_only_member + - billing + - support + type: string + x-struct: null + x-validate: null + updated_at: + description: The timestamp of when the member was last updated. + format: date-time + type: string + x-struct: null + x-validate: null + user: + $ref: '#/components/schemas/MemberUser' + required: + - id + - role + - user + - created_at + - updated_at + title: Member + type: object + x-struct: Elixir.ControlWeb.V1.Specs.Member + x-validate: null ObjectRecipientReference: description: An object reference. example: @@ -3786,21 +4437,58 @@ components: type: object x-struct: null x-validate: null - PageInfo: - description: The information about a paginated result. + PaginatedMemberResponse: + description: A paginated list of Member. Contains a list of entries and page information. example: - after: null - before: null - page_size: 25 + entries: + - created_at: "2024-01-15T10:30:00Z" + id: d4b8e8e0-1234-5678-9abc-def012345678 + role: admin + updated_at: "2024-06-20T14:45:00Z" + user: + avatar_url: https://www.gravatar.com/avatar/abc123 + created_at: "2024-01-10T08:00:00Z" + email: jane@example.com + id: a1b2c3d4-5678-9abc-def0-123456789abc + name: Jane Doe + updated_at: "2024-06-18T12:00:00Z" + page_info: + after: null + before: null + page_size: 25 properties: - after: - description: The cursor to fetch entries after. Will only be present if there are more entries to fetch. - nullable: true - type: string - x-struct: null - x-validate: null - before: - description: The cursor to fetch entries before. Will only be present if there are more entries to fetch before the current page. + entries: + description: A list of entries. + items: + $ref: '#/components/schemas/Member' + nullable: false + type: array + x-struct: null + x-validate: null + page_info: + $ref: '#/components/schemas/PageInfo' + required: + - entries + - page_info + title: PaginatedMemberResponse + type: object + x-struct: null + x-validate: null + PageInfo: + description: The information about a paginated result. + example: + after: null + before: null + page_size: 25 + properties: + after: + description: The cursor to fetch entries after. Will only be present if there are more entries to fetch. + nullable: true + type: string + x-struct: null + x-validate: null + before: + description: The cursor to fetch entries before. Will only be present if there are more entries to fetch before the current page. nullable: true type: string x-struct: null @@ -3890,6 +4578,95 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.Variable x-validate: null + WorkflowUpdateUserStep: + description: An update user step. Updates properties of a specific user referenced in the workflow. + example: + description: Update user step description. + name: Update user + ref: update_user_1 + settings: + recipient_gid: gid://Object/$users/user-123 + recipient_mode: reference + update_properties: '{"name": "Updated User"}' + type: update_user + properties: + conditions: + anyOf: + - $ref: '#/components/schemas/ConditionGroup' + - nullable: true + x-struct: null + x-validate: null + description: A conditions object that describes one or more conditions to be met in order for the step to be executed. + type: object + x-struct: null + x-validate: null + description: + description: An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. + example: Update user step description. + nullable: true + type: string + x-struct: null + x-validate: null + name: + description: A name for the workflow step. + example: Update user + nullable: true + type: string + x-struct: null + x-validate: null + ref: + description: The reference key of the workflow step. Must be unique per workflow. + example: update_user_1 + type: string + x-struct: null + x-validate: null + settings: + description: The settings for the update user step. + properties: + recipient_gid: + description: 'The global identifier (GID) of the user to update. Required when recipient_mode is ''reference''. Format: gid://Object/$users/{id}' + example: gid://Object/$users/user-123 + nullable: true + type: string + x-struct: null + x-validate: null + recipient_mode: + description: The recipient mode determining how the user is selected. 'current' uses the workflow's current user. 'reference' uses a specific user ID. + enum: + - current + - reference + example: reference + type: string + x-struct: null + x-validate: null + update_properties: + description: A JSON string or Liquid template that evaluates to the properties to update on the user. + example: '{"name": "Updated User", "email": "user@example.com"}' + type: string + x-struct: null + x-validate: null + required: + - recipient_mode + - update_properties + type: object + x-struct: null + x-validate: null + type: + description: The type of the workflow step. + enum: + - update_user + example: update_user + type: string + x-struct: null + x-validate: null + required: + - type + - ref + - settings + title: WorkflowUpdateUserStep + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowUpdateUserStep + x-validate: null PaginatedTranslationResponse: description: A paginated list of Translation. Contains a list of entries and page information. example: @@ -4167,6 +4944,13 @@ components: source: user updated_at: "2021-01-01T00:00:00Z" properties: + archived_at: + description: The timestamp of when the channel group was archived (soft deleted). + format: date-time + nullable: true + type: string + x-struct: null + x-validate: null channel_rules: description: Rules for determining which channels should be used. items: @@ -4290,12 +5074,12 @@ components: - contains_all - not_contains_all - is_timestamp_before - - is_timestamp_after - - is_timestamp_before_date - - is_timestamp_after_date + - is_timestamp_on_or_after - is_timestamp_between - empty - not_empty + - exists + - not_exists - is_timestamp - is_audience_member - is_not_audience_member @@ -4466,6 +5250,7 @@ components: - $ref: '#/components/schemas/WorkflowEmailStep' - $ref: '#/components/schemas/WorkflowBranchStep' - $ref: '#/components/schemas/WorkflowDelayStep' + - $ref: '#/components/schemas/WorkflowRandomCohortStep' description: A step within a broadcast. Each step, regardless of its type, share a common set of core attributes (`type`, `ref`, `name`, `description`, `conditions`). type: object x-struct: null @@ -4604,6 +5389,76 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.WorkflowWebhookStep x-validate: null + WorkflowUpdateDataStep: + description: An update data function step. Merges data into the workflow's `data` scope for use in subsequent steps. + example: + description: Update data step description. + name: Update data + ref: update_data_1 + settings: + data: '{"key": "value"}' + type: update_data + properties: + conditions: + anyOf: + - $ref: '#/components/schemas/ConditionGroup' + - nullable: true + x-struct: null + x-validate: null + description: A conditions object that describes one or more conditions to be met in order for the step to be executed. + type: object + x-struct: null + x-validate: null + description: + description: An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. + example: Update data step description. + nullable: true + type: string + x-struct: null + x-validate: null + name: + description: A name for the workflow step. + example: Update data + nullable: true + type: string + x-struct: null + x-validate: null + ref: + description: The reference key of the workflow step. Must be unique per workflow. + example: update_data_1 + type: string + x-struct: null + x-validate: null + settings: + description: The settings for the update data step. + properties: + data: + description: A JSON string or Liquid template that evaluates to the data to merge into the workflow's data scope. + example: '{"key": "value"}' + type: string + x-struct: null + x-validate: null + required: + - data + type: object + x-struct: null + x-validate: null + type: + description: The type of the workflow step. + enum: + - update_data + example: update_data + type: string + x-struct: null + x-validate: null + required: + - type + - ref + - settings + title: WorkflowUpdateDataStep + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowUpdateDataStep + x-validate: null WrappedWorkflowResponse: description: Wraps the Workflow response under the `workflow` key. example: @@ -4930,6 +5785,26 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.ChatTemplate x-validate: null + WrappedChannelGroupRequestRequest: + description: Wraps the ChannelGroupRequest request under the channel_group key. + example: + channel_group: + channel_rules: + - channel_key: push-fcm + index: 0 + rule_type: always + channel_type: push + name: Push Notification Group + operator: any + properties: + channel_group: + $ref: '#/components/schemas/ChannelGroupRequest' + required: + - channel_group + title: WrappedChannelGroupRequestRequest + type: object + x-struct: null + x-validate: null Guide: description: A guide defines an in-app guide that can be displayed to users based on priority and other conditions. example: @@ -5084,6 +5959,84 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.Guide x-validate: null + WorkflowUpdateObjectStep: + description: An update object step. Updates properties of a specific object referenced in the workflow. + example: + description: Update object step description. + name: Update object + ref: update_object_1 + settings: + recipient_gid: gid://Object/projects/123 + update_properties: '{"status": "active"}' + type: update_object + properties: + conditions: + anyOf: + - $ref: '#/components/schemas/ConditionGroup' + - nullable: true + x-struct: null + x-validate: null + description: A conditions object that describes one or more conditions to be met in order for the step to be executed. + type: object + x-struct: null + x-validate: null + description: + description: An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. + example: Update object step description. + nullable: true + type: string + x-struct: null + x-validate: null + name: + description: A name for the workflow step. + example: Update object + nullable: true + type: string + x-struct: null + x-validate: null + ref: + description: The reference key of the workflow step. Must be unique per workflow. + example: update_object_1 + type: string + x-struct: null + x-validate: null + settings: + description: The settings for the update object step. + properties: + recipient_gid: + description: 'The global identifier (GID) of the object to update. Format: gid://Object/{collection}/{id}' + example: gid://Object/projects/123 + type: string + x-struct: null + x-validate: null + update_properties: + description: A JSON string or Liquid template that evaluates to the properties to update on the object. + example: '{"status": "active", "updated_at": "{{ timestamp }}"}' + type: string + x-struct: null + x-validate: null + required: + - recipient_gid + - update_properties + type: object + x-struct: null + x-validate: null + type: + description: The type of the workflow step. + enum: + - update_object + example: update_object + type: string + x-struct: null + x-validate: null + required: + - type + - ref + - settings + title: WorkflowUpdateObjectStep + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowUpdateObjectStep + x-validate: null WrappedMessageTypeRequestRequest: description: Wraps the MessageTypeRequest request under the message_type key. example: @@ -5192,7 +6145,7 @@ components: x-validate: null created_by: anyOf: - - $ref: '#/components/schemas/WorkflowUserInfo' + - $ref: '#/components/schemas/MemberUser' - nullable: true x-struct: null x-validate: null @@ -5279,7 +6232,7 @@ components: x-validate: null updated_by: anyOf: - - $ref: '#/components/schemas/WorkflowUserInfo' + - $ref: '#/components/schemas/MemberUser' - nullable: true x-struct: null x-validate: null @@ -5704,37 +6657,6 @@ components: type: object x-struct: null x-validate: null - WorkflowUserInfo: - description: Information about a user within the Knock dashboard. Not to be confused with an external user (recipient) of a workflow. - example: - email: john@example.com - id: user_123 - name: John Doe - properties: - email: - description: The user's email address. - format: email - type: string - x-struct: null - x-validate: null - id: - description: The user's unique identifier. - type: string - x-struct: null - x-validate: null - name: - description: The user's name. - nullable: true - type: string - x-struct: null - x-validate: null - required: - - id - - email - title: WorkflowUserInfo - type: object - x-struct: Elixir.ControlWeb.V1.Specs.WorkflowUserInfo - x-validate: null EmailMarkdownBlock: description: A markdown block in an email template. example: @@ -5864,6 +6786,7 @@ components: This is **bold** and this is *italic*. description: A description of the markdown field + placeholder: A placeholder for the markdown field required: true type: markdown properties: @@ -5893,7 +6816,14 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true + type: string + x-struct: null + x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true type: string x-struct: null x-validate: null @@ -5931,6 +6861,7 @@ components: description: A description of the textarea field max_length: 1000 min_length: 10 + placeholder: A placeholder for the textarea field required: true type: textarea properties: @@ -5958,7 +6889,8 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true type: string x-struct: null x-validate: null @@ -5972,6 +6904,12 @@ components: type: integer x-struct: null x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true + type: string + x-struct: null + x-validate: null required: description: Whether the field is required. example: true @@ -6430,21 +7368,76 @@ components: type: object x-struct: null x-validate: null - PreviewWorkflowTemplateRequest: - description: A request to preview a workflow template. + MemberUser: + description: Information about a user within the Knock dashboard. Not to be confused with an external user (recipient) of a workflow. example: - actor: dnedry - data: - park_id: 1 - recipient: dnedry - tenant: acme-corp + avatar_url: https://www.gravatar.com/avatar/abc123 + created_at: "2024-01-10T08:00:00Z" + email: jane@example.com + id: a1b2c3d4-5678-9abc-def0-123456789abc + name: Jane Doe + updated_at: "2024-06-18T12:00:00Z" properties: - actor: - anyOf: - - $ref: '#/components/schemas/RecipientReference' - - nullable: true - x-struct: null - x-validate: null + avatar_url: + description: The URL of the user's avatar image. + nullable: true + type: string + x-struct: null + x-validate: null + created_at: + description: The timestamp of when the user was created. + format: date-time + type: string + x-struct: null + x-validate: null + email: + description: The user's email address. + format: email + type: string + x-struct: null + x-validate: null + id: + description: The user's unique identifier. + format: uuid + type: string + x-struct: null + x-validate: null + name: + description: The user's display name. + nullable: true + type: string + x-struct: null + x-validate: null + updated_at: + description: The timestamp of when the user was last updated. + format: date-time + type: string + x-struct: null + x-validate: null + required: + - id + - email + - created_at + - updated_at + title: MemberUser + type: object + x-struct: Elixir.ControlWeb.V1.Specs.MemberUser + x-validate: null + PreviewWorkflowTemplateRequest: + description: A request to preview a workflow template. + example: + actor: dnedry + data: + park_id: 1 + recipient: dnedry + tenant: acme-corp + properties: + actor: + anyOf: + - $ref: '#/components/schemas/RecipientReference' + - nullable: true + x-struct: null + x-validate: null description: The actor to reference in the the workflow run. type: object x-struct: null @@ -6610,6 +7603,45 @@ components: type: object x-struct: null x-validate: null + WorkflowRandomCohortStepBranch: + description: A cohort branch in an experiment step. + example: + name: Control + percentage: "50" + steps: [] + terminates: false + properties: + name: + description: The name of the cohort branch. + example: Control + type: string + x-struct: null + x-validate: null + percentage: + description: The percentage of recipients to assign to this cohort. Must be between 0 and 100 with at most 1 decimal place. All branch percentages must sum to 100. Sent as a number in requests; returned as a decimal string in responses (e.g. "50", "33.3"). + example: "50" + type: string + x-struct: null + x-validate: null + steps: + description: A list of steps that will be executed for recipients assigned to this cohort. + items: + $ref: '#/components/schemas/WorkflowStep' + type: array + x-struct: null + x-validate: null + terminates: + description: If the workflow should halt at the end of the branch. Defaults to false if not provided. + example: false + type: boolean + x-struct: null + x-validate: null + required: + - percentage + title: WorkflowRandomCohortStepBranch + type: object + x-struct: Elixir.ControlWeb.V1.Specs.WorkflowRandomCohortStep.CohortBranch + x-validate: null RunWorkflowResponse: description: A response to a run workflow request. example: @@ -6627,6 +7659,50 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.RunWorkflowResponse x-validate: null + RequestTemplateQueryParams: + description: The query params of the request. Can be a template string or a list of key-value pairs. + example: + - key: key + value: value + oneOf: + - description: A template string that should resolve to a JSON object representing the query params. + example: '{{ data.request_query_params }}' + title: RequestTemplateQueryParamsString + type: string + x-struct: null + x-validate: null + - description: A list of key-value pairs for the request query params. Each object should contain key and value fields with string values. + example: + - key: key + value: value + items: + properties: + key: + description: The key of the query param. + example: key + type: string + x-struct: null + x-validate: null + value: + description: The value of the query param. + example: value + type: string + x-struct: null + x-validate: null + required: + - key + - value + type: object + x-struct: null + x-validate: null + title: RequestTemplateQueryParamsArray + type: array + x-struct: null + x-validate: null + title: RequestTemplateQueryParams + type: object + x-struct: null + x-validate: null Branch: description: A branch object. example: @@ -6675,6 +7751,50 @@ components: type: object x-struct: Elixir.ControlWeb.V1.Specs.Branch x-validate: null + RequestTemplateHeaders: + description: The headers of the request. Can be a template string or a list of key-value pairs. + example: + - key: X-API-Key + value: "1234567890" + oneOf: + - description: A template string that should resolve to a JSON object representing the headers. + example: '{{ data.request_headers }}' + title: RequestTemplateHeadersString + type: string + x-struct: null + x-validate: null + - description: A list of key-value pairs for the request headers. Each object should contain key and value fields with string values. + example: + - key: X-API-Key + value: "1234567890" + items: + properties: + key: + description: The key of the header. + example: X-API-Key + type: string + x-struct: null + x-validate: null + value: + description: The value of the header. + example: "1234567890" + type: string + x-struct: null + x-validate: null + required: + - key + - value + type: object + x-struct: null + x-validate: null + title: RequestTemplateHeadersArray + type: array + x-struct: null + x-validate: null + title: RequestTemplateHeaders + type: object + x-struct: null + x-validate: null Partial: description: A partial is a reusable piece of content that can be used in a template. example: @@ -6726,6 +7846,7 @@ components: - $ref: '#/components/schemas/MessageTypeBooleanField' - $ref: '#/components/schemas/MessageTypeButtonField' - $ref: '#/components/schemas/MessageTypeImageField' + - $ref: '#/components/schemas/MessageTypeJsonField' - $ref: '#/components/schemas/MessageTypeMarkdownField' - $ref: '#/components/schemas/MessageTypeMultiSelectField' - $ref: '#/components/schemas/MessageTypeSelectField' @@ -7139,7 +8260,8 @@ components: x-struct: null x-validate: null description: - example: A description of the field, used in the UI + example: A description of the field, used in the UI as a hint text. + nullable: true type: string x-struct: null x-validate: null @@ -7167,6 +8289,12 @@ components: type: array x-struct: null x-validate: null + placeholder: + example: A placeholder for the field. + nullable: true + type: string + x-struct: null + x-validate: null required: description: Whether the field is required. example: true @@ -7380,12 +8508,12 @@ components: - contains_all - not_contains_all - is_timestamp_before - - is_timestamp_after - - is_timestamp_before_date - - is_timestamp_after_date + - is_timestamp_on_or_after - is_timestamp_between - empty - not_empty + - exists + - not_exists - is_timestamp - is_audience_member - is_not_audience_member @@ -7574,22 +8702,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - environment, err := client.Environments.Get(context.TODO(), "development") - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", environment.HidePiiData) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + environment, err := client.Environments.Get(context.TODO(), "development") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", environment.HidePiiData) } /v1/branches: get: @@ -7697,24 +8825,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Branches.List(context.TODO(), knockmapi.BranchListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Branches.List(context.TODO(), knockmapi.BranchListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/workflows/{workflow_key}/validate: put: @@ -7900,40 +9028,40 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Workflows.Validate( - context.TODO(), - "workflow_key", - knockmapi.WorkflowValidateParams{ - Environment: "development", - Workflow: knockmapi.WorkflowValidateParamsWorkflow{ - Name: "My Workflow", - Steps: []knockmapi.WorkflowStepUnionParam{knockmapi.WorkflowStepUnionParam{ - OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ - Ref: "channel_1", - Template: knockmapi.InAppFeedTemplateParam{ - MarkdownBody: "Hello **{{ recipient.name }}**", - }, - Type: knockmapi.WorkflowInAppFeedStepTypeChannel, - }, - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Workflow) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Workflows.Validate( + context.TODO(), + "workflow_key", + knockmapi.WorkflowValidateParams{ + Environment: "development", + Workflow: knockmapi.WorkflowValidateParamsWorkflow{ + Name: "My Workflow", + Steps: []knockmapi.WorkflowStepUnionParam{{ + OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ + Ref: "channel_1", + Template: knockmapi.InAppFeedTemplateParam{ + MarkdownBody: "Hello **{{ recipient.name }}**", + }, + Type: knockmapi.WorkflowInAppFeedStepTypeChannel, + }, + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Workflow) } /v1/workflows/{workflow_key}/run: put: @@ -8015,31 +9143,31 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Workflows.Run( - context.TODO(), - "workflow_key", - knockmapi.WorkflowRunParams{ - Environment: "development", - Recipients: []knockmapi.WorkflowRunParamsRecipientUnion{knockmapi.WorkflowRunParamsRecipientUnion{ - OfString: knockmapi.String("dnedry"), - }}, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.WorkflowRunID) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Workflows.Run( + context.TODO(), + "workflow_key", + knockmapi.WorkflowRunParams{ + Environment: "development", + Recipients: []knockmapi.WorkflowRunParamsRecipientUnion{{ + OfString: knockmapi.String("dnedry"), + }}, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.WorkflowRunID) } /v1/email_layouts: get: @@ -8178,24 +9306,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.EmailLayouts.List(context.TODO(), knockmapi.EmailLayoutListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.EmailLayouts.List(context.TODO(), knockmapi.EmailLayoutListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/guides/{guide_key}: delete: @@ -8262,22 +9390,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Guides.Archive(context.TODO(), "guide_key") - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Result) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Guides.Archive(context.TODO(), "guide_key") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Result) } get: callbacks: {} @@ -8363,28 +9491,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - guide, err := client.Guides.Get( - context.TODO(), - "guide_key", - knockmapi.GuideGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", guide.TargetAudienceID) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + guide, err := client.Guides.Get( + context.TODO(), + "guide_key", + knockmapi.GuideGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", guide.TargetAudienceID) } put: callbacks: {} @@ -8584,38 +9712,38 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Guides.Upsert( - context.TODO(), - "guide_key", - knockmapi.GuideUpsertParams{ - Environment: "development", - Guide: knockmapi.GuideUpsertParamsGuide{ - ChannelKey: "in-app-guide", - Name: "Getting Started Guide", - Steps: []knockmapi.GuideStepParam{knockmapi.GuideStepParam{ - Ref: "welcome-step", - SchemaKey: "tooltip", - SchemaSemver: "1.0.0", - SchemaVariantKey: "default", - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Guide) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Guides.Upsert( + context.TODO(), + "guide_key", + knockmapi.GuideUpsertParams{ + Environment: "development", + Guide: knockmapi.GuideUpsertParamsGuide{ + ChannelKey: "in-app-guide", + Name: "Getting Started Guide", + Steps: []knockmapi.GuideStepParam{{ + Ref: "welcome-step", + SchemaKey: "tooltip", + SchemaSemver: "1.0.0", + SchemaVariantKey: "default", + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Guide) } /v1/broadcasts/{broadcast_key}/send: put: @@ -8732,28 +9860,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Broadcasts.Send( - context.TODO(), - "broadcast_key", - knockmapi.BroadcastSendParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Broadcast) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Broadcasts.Send( + context.TODO(), + "broadcast_key", + knockmapi.BroadcastSendParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Broadcast) } /v1/guides: get: @@ -8911,24 +10039,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Guides.List(context.TODO(), knockmapi.GuideListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Guides.List(context.TODO(), knockmapi.GuideListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/broadcasts/{broadcast_key}/validate: put: @@ -9094,40 +10222,40 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Broadcasts.Validate( - context.TODO(), - "broadcast_key", - knockmapi.BroadcastValidateParams{ - Environment: "development", - Broadcast: knockmapi.BroadcastRequestParam{ - Name: "My Broadcast", - Steps: []knockmapi.BroadcastRequestStepUnionParam{knockmapi.BroadcastRequestStepUnionParam{ - OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ - Ref: "channel_1", - Template: knockmapi.InAppFeedTemplateParam{ - MarkdownBody: "Hello **{{ recipient.name }}**", - }, - Type: knockmapi.WorkflowInAppFeedStepTypeChannel, - }, - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Broadcast) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Broadcasts.Validate( + context.TODO(), + "broadcast_key", + knockmapi.BroadcastValidateParams{ + Environment: "development", + Broadcast: knockmapi.BroadcastRequestParam{ + Name: "My Broadcast", + Steps: []knockmapi.BroadcastRequestStepUnionParam{{ + OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ + Ref: "channel_1", + Template: knockmapi.InAppFeedTemplateParam{ + MarkdownBody: "Hello **{{ recipient.name }}**", + }, + Type: knockmapi.WorkflowInAppFeedStepTypeChannel, + }, + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Broadcast) } /v1/translations: get: @@ -9289,24 +10417,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Translations.List(context.TODO(), knockmapi.TranslationListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Translations.List(context.TODO(), knockmapi.TranslationListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/workflows/{workflow_key}/steps/{step_ref}/preview_template: post: @@ -9398,32 +10526,32 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Workflows.Steps.PreviewTemplate( - context.TODO(), - "step_ref", - knockmapi.WorkflowStepPreviewTemplateParams{ - WorkflowKey: "workflow_key", - Environment: "development", - Recipient: knockmapi.WorkflowStepPreviewTemplateParamsRecipientUnion{ - OfString: knockmapi.String("dnedry"), - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.ContentType) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Workflows.Steps.PreviewTemplate( + context.TODO(), + "step_ref", + knockmapi.WorkflowStepPreviewTemplateParams{ + WorkflowKey: "workflow_key", + Environment: "development", + Recipient: knockmapi.WorkflowStepPreviewTemplateParamsRecipientUnion{ + OfString: knockmapi.String("dnedry"), + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.ContentType) } /v1/guides/{guide_key}/activate: put: @@ -9549,28 +10677,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Guides.Activate( - context.TODO(), - "guide_key", - knockmapi.GuideActivateParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Guide) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Guides.Activate( + context.TODO(), + "guide_key", + knockmapi.GuideActivateParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Guide) } /v1/partials: get: @@ -9718,24 +10846,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Partials.List(context.TODO(), knockmapi.PartialListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Partials.List(context.TODO(), knockmapi.PartialListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/partials/{partial_key}: get: @@ -9822,28 +10950,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - partial, err := client.Partials.Get( - context.TODO(), - "partial_key", - knockmapi.PartialGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", partial.Valid) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + partial, err := client.Partials.Get( + context.TODO(), + "partial_key", + knockmapi.PartialGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", partial.Valid) } put: callbacks: {} @@ -9911,8 +11039,19 @@ paths: example: partial: content:

Hello, world!

+ description: This is a test partial + input_schema: + - key: text_field + label: My text field + settings: + description: A description of the text field + max_length: 100 + min_length: 10 + required: true + type: text name: My Partial type: html + visual_block_enabled: true properties: partial: $ref: '#/components/schemas/PartialRequest' @@ -10004,33 +11143,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Partials.Upsert( - context.TODO(), - "partial_key", - knockmapi.PartialUpsertParams{ - Environment: "development", - Partial: knockmapi.PartialUpsertParamsPartial{ - Content: "

Hello, world!

", - Name: "My Partial", - Type: "html", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Partial) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Partials.Upsert( + context.TODO(), + "partial_key", + knockmapi.PartialUpsertParams{ + Environment: "development", + Partial: knockmapi.PartialUpsertParamsPartial{ + Content: "

Hello, world!

", + Name: "My Partial", + Type: "html", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Partial) } /v1/channels: get: @@ -10140,83 +11279,44 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Channels.List(context.TODO(), knockmapi.ChannelListParams{ - - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Channels.List(context.TODO(), knockmapi.ChannelListParams{}) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } - /v1/email_layouts/{email_layout_key}: - get: + /v1/members/{id}: + delete: callbacks: {} - description: Retrieve an email layout by its key, in a given environment. - operationId: getEmailLayout + description: Removes a member from the account. + operationId: removeMember parameters: - - description: The key of the email layout to show. + - description: The ID of the member to remove. in: path - name: email_layout_key - required: true - schema: - type: string - x-struct: null - x-validate: null - - description: The environment slug. - in: query - name: environment + name: id required: true schema: - example: development - type: string - x-struct: null - x-validate: null - - description: The slug of a branch to use. This option can only be used when `environment` is `"development"`. - in: query - name: branch - required: false - schema: - example: feature-branch + format: uuid type: string x-struct: null x-validate: null - - description: Whether to annotate the resource. Only used in the Knock CLI. - in: query - name: annotate - required: false - schema: - type: boolean - x-struct: null - x-validate: null - - description: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. - in: query - name: hide_uncommitted_changes - required: false - schema: - type: boolean - x-struct: null - x-validate: null responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/EmailLayout' - description: OK - summary: Get email layout + "204": + description: No Content + summary: Remove a member tags: - - Email layouts + - Members x-stainless-snippets: typescript: |- import KnockMgmt from '@knocklabs/mgmt'; @@ -10225,11 +11325,7 @@ paths: serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted }); - const emailLayout = await client.emailLayouts.retrieve('email_layout_key', { - environment: 'development', - }); - - console.log(emailLayout.created_at); + await client.members.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); python: |- import os from knock_mapi import KnockMgmt @@ -10237,62 +11333,229 @@ paths: client = KnockMgmt( service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted ) - email_layout = client.email_layouts.retrieve( - email_layout_key="email_layout_key", - environment="development", + client.members.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - print(email_layout.created_at) go: | package main import ( - "context" - "fmt" + "context" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - emailLayout, err := client.EmailLayouts.Get( - context.TODO(), - "email_layout_key", - knockmapi.EmailLayoutGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", emailLayout.CreatedAt) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + err := client.Members.Delete(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + if err != nil { + panic(err.Error()) + } } - put: + get: callbacks: {} - description: | - Updates an email layout, or creates a new one if it does not yet exist. - - Note: this endpoint only operates in the "development" environment. - operationId: upsertEmailLayout + description: Returns a single member by their ID. + operationId: getMember parameters: - - description: The key of the email layout to upsert. + - description: The ID of the member to retrieve. in: path - name: email_layout_key + name: id required: true schema: + format: uuid type: string x-struct: null x-validate: null - - description: The environment slug. - in: query - name: environment - required: true - schema: - example: development - type: string - x-struct: null + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Member' + description: OK + summary: Get a member + tags: + - Members + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + const member = await client.members.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); + + console.log(member.id); + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + member = client.members.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + print(member.id) + go: | + package main + + import ( + "context" + "fmt" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + member, err := client.Members.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", member.ID) + } + /v1/email_layouts/{email_layout_key}: + get: + callbacks: {} + description: Retrieve an email layout by its key, in a given environment. + operationId: getEmailLayout + parameters: + - description: The key of the email layout to show. + in: path + name: email_layout_key + required: true + schema: + type: string + x-struct: null + x-validate: null + - description: The environment slug. + in: query + name: environment + required: true + schema: + example: development + type: string + x-struct: null + x-validate: null + - description: The slug of a branch to use. This option can only be used when `environment` is `"development"`. + in: query + name: branch + required: false + schema: + example: feature-branch + type: string + x-struct: null + x-validate: null + - description: Whether to annotate the resource. Only used in the Knock CLI. + in: query + name: annotate + required: false + schema: + type: boolean + x-struct: null + x-validate: null + - description: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. + in: query + name: hide_uncommitted_changes + required: false + schema: + type: boolean + x-struct: null + x-validate: null + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/EmailLayout' + description: OK + summary: Get email layout + tags: + - Email layouts + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + const emailLayout = await client.emailLayouts.retrieve('email_layout_key', { + environment: 'development', + }); + + console.log(emailLayout.created_at); + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + email_layout = client.email_layouts.retrieve( + email_layout_key="email_layout_key", + environment="development", + ) + print(email_layout.created_at) + go: | + package main + + import ( + "context" + "fmt" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + emailLayout, err := client.EmailLayouts.Get( + context.TODO(), + "email_layout_key", + knockmapi.EmailLayoutGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", emailLayout.CreatedAt) + } + put: + callbacks: {} + description: | + Updates an email layout, or creates a new one if it does not yet exist. + + Note: this endpoint only operates in the "development" environment. + operationId: upsertEmailLayout + parameters: + - description: The key of the email layout to upsert. + in: path + name: email_layout_key + required: true + schema: + type: string + x-struct: null + x-validate: null + - description: The environment slug. + in: query + name: environment + required: true + schema: + example: development + type: string + x-struct: null x-validate: null - description: The slug of a branch to use. This option can only be used when `environment` is `"development"`. in: query @@ -10422,33 +11685,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.EmailLayouts.Upsert( - context.TODO(), - "email_layout_key", - knockmapi.EmailLayoutUpsertParams{ - Environment: "development", - EmailLayout: knockmapi.EmailLayoutUpsertParamsEmailLayout{ - HTMLLayout: "Hello, world!", - Name: "Transactional", - TextLayout: "Hello, world!", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.EmailLayout) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.EmailLayouts.Upsert( + context.TODO(), + "email_layout_key", + knockmapi.EmailLayoutUpsertParams{ + Environment: "development", + EmailLayout: knockmapi.EmailLayoutUpsertParamsEmailLayout{ + HTMLLayout: "Hello, world!", + Name: "Transactional", + TextLayout: "Hello, world!", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.EmailLayout) } /v1/channel_groups: get: @@ -10562,24 +11825,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.ChannelGroups.List(context.TODO(), knockmapi.ChannelGroupListParams{ - - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.ChannelGroups.List(context.TODO(), knockmapi.ChannelGroupListParams{}) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/workflows: get: @@ -10759,24 +12020,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Workflows.List(context.TODO(), knockmapi.WorkflowListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Workflows.List(context.TODO(), knockmapi.WorkflowListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/broadcasts: get: @@ -10931,24 +12192,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Broadcasts.List(context.TODO(), knockmapi.BroadcastListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Broadcasts.List(context.TODO(), knockmapi.BroadcastListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/translations/{locale_code}/validate: put: @@ -11066,32 +12327,32 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Translations.Validate( - context.TODO(), - "locale_code", - knockmapi.TranslationValidateParams{ - Environment: "development", - Translation: knockmapi.TranslationValidateParamsTranslation{ - Content: `{"hello":"Hello, world!"}`, - Format: "json", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Translation) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Translations.Validate( + context.TODO(), + "locale_code", + knockmapi.TranslationValidateParams{ + Environment: "development", + Translation: knockmapi.TranslationValidateParamsTranslation{ + Content: `{"hello":"Hello, world!"}`, + Format: "json", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Translation) } /v1/whoami: get: @@ -11133,22 +12394,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Auth.Verify(context.TODO()) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.UserID) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Auth.Verify(context.TODO()) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.UserID) } /v1/commits/{id}: get: @@ -11201,22 +12462,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - commit, err := client.Commits.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", commit.ID) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + commit, err := client.Commits.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", commit.ID) } /v1/variables: get: @@ -11334,24 +12595,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Variables.List(context.TODO(), knockmapi.VariableListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Variables.List(context.TODO(), knockmapi.VariableListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/workflows/{workflow_key}/activate: put: @@ -11512,29 +12773,29 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Workflows.Activate( - context.TODO(), - "workflow_key", - knockmapi.WorkflowActivateParams{ - Environment: "development", - Status: true, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Workflow) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Workflows.Activate( + context.TODO(), + "workflow_key", + knockmapi.WorkflowActivateParams{ + Environment: "development", + Status: true, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Workflow) } /v1/partials/{partial_key}/validate: put: @@ -11579,8 +12840,19 @@ paths: example: partial: content:

Hello, world!

+ description: This is a test partial + input_schema: + - key: text_field + label: My text field + settings: + description: A description of the text field + max_length: 100 + min_length: 10 + required: true + type: text name: My Partial type: html + visual_block_enabled: true properties: partial: $ref: '#/components/schemas/PartialRequest' @@ -11672,33 +12944,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Partials.Validate( - context.TODO(), - "partial_key", - knockmapi.PartialValidateParams{ - Environment: "development", - Partial: knockmapi.PartialValidateParamsPartial{ - Content: "

Hello, world!

", - Name: "My Partial", - Type: "html", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Partial) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Partials.Validate( + context.TODO(), + "partial_key", + knockmapi.PartialValidateParams{ + Environment: "development", + Partial: knockmapi.PartialValidateParamsPartial{ + Content: "

Hello, world!

", + Name: "My Partial", + Type: "html", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Partial) } /v1/message_types/{message_type_key}/validate: put: @@ -11855,33 +13127,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.MessageTypes.Validate( - context.TODO(), - "email", - knockmapi.MessageTypeValidateParams{ - Environment: "development", - MessageType: knockmapi.MessageTypeValidateParamsMessageType{ - Description: knockmapi.String("This is a message type"), - Name: "My Message Type", - Preview: "
Hello, world!
", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.MessageType) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.MessageTypes.Validate( + context.TODO(), + "email", + knockmapi.MessageTypeValidateParams{ + Environment: "development", + MessageType: knockmapi.MessageTypeValidateParamsMessageType{ + Description: knockmapi.String("This is a message type"), + Name: "My Message Type", + Preview: "
Hello, world!
", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.MessageType) } /v1/translations/{locale_code}: get: @@ -12006,28 +13278,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - translation, err := client.Translations.Get( - context.TODO(), - "locale_code", - knockmapi.TranslationGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", translation.Translation) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + translation, err := client.Translations.Get( + context.TODO(), + "locale_code", + knockmapi.TranslationGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", translation.Translation) } put: callbacks: {} @@ -12189,33 +13461,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Translations.Upsert( - context.TODO(), - "locale_code", - knockmapi.TranslationUpsertParams{ - Environment: "development", - Namespace: "namespace", - Translation: knockmapi.TranslationUpsertParamsTranslation{ - Content: `{"hello":"Hello, world!"}`, - Format: "json", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Translation) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Translations.Upsert( + context.TODO(), + "locale_code", + knockmapi.TranslationUpsertParams{ + Environment: "development", + Namespace: "namespace", + Translation: knockmapi.TranslationUpsertParamsTranslation{ + Content: `{"hello":"Hello, world!"}`, + Format: "json", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Translation) } /v1/environments: get: @@ -12317,24 +13589,22 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Environments.List(context.TODO(), knockmapi.EnvironmentListParams{ - - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Environments.List(context.TODO(), knockmapi.EnvironmentListParams{}) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/email_layouts/{email_layout_key}/validate: put: @@ -12466,33 +13736,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.EmailLayouts.Validate( - context.TODO(), - "email_layout_key", - knockmapi.EmailLayoutValidateParams{ - Environment: "development", - EmailLayout: knockmapi.EmailLayoutValidateParamsEmailLayout{ - HTMLLayout: "Hello, world!", - Name: "Transactional", - TextLayout: "Hello, world!", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.EmailLayout) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.EmailLayouts.Validate( + context.TODO(), + "email_layout_key", + knockmapi.EmailLayoutValidateParams{ + Environment: "development", + EmailLayout: knockmapi.EmailLayoutValidateParamsEmailLayout{ + HTMLLayout: "Hello, world!", + Name: "Transactional", + TextLayout: "Hello, world!", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.EmailLayout) } /v1/commits/{id}/promote: put: @@ -12536,9 +13806,343 @@ paths: x-struct: null x-validate: null description: OK - summary: Promote one commit + summary: Promote one commit + tags: + - Commits + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + const response = await client.commits.promoteOne('id'); + + console.log(response.commit); + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + response = client.commits.promote_one( + "id", + ) + print(response.commit) + go: | + package main + + import ( + "context" + "fmt" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Commits.PromoteOne(context.TODO(), "id") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Commit) + } + /v1/guides/{guide_key}/validate: + put: + callbacks: {} + description: | + Validates a guide payload without persisting it. + + Note: Validating a guide is only done in the development environment context. + operationId: validateGuide + parameters: + - description: The key of the guide. + in: path + name: guide_key + required: true + schema: + type: string + x-struct: null + x-validate: null + - description: The environment slug. + in: query + name: environment + required: true + schema: + example: development + type: string + x-struct: null + x-validate: null + - description: The slug of a branch to use. This option can only be used when `environment` is `"development"`. + in: query + name: branch + required: false + schema: + example: feature-branch + type: string + x-struct: null + x-validate: null + requestBody: + content: + application/json: + schema: + description: Wraps the GuideRequest request under the guide key. + example: + guide: + activation_url_patterns: + - directive: allow + pathname: /dashboard/* + channel_key: in-app-guide + description: A guide to help users get started with the application + name: Getting Started Guide + steps: + - name: Welcome to the App + ref: welcome-step + schema_key: tooltip + schema_semver: 1.0.0 + schema_variant_key: default + values: + text_field: value + target_audience_id: null + target_property_conditions: + all: + - argument: some_property + operator: equal_to + variable: recipient.property + properties: + guide: + $ref: '#/components/schemas/GuideRequest' + required: + - guide + title: WrappedGuideRequestRequest + type: object + x-struct: null + x-validate: null + description: Params + required: false + responses: + "200": + content: + application/json: + schema: + description: Wraps the Guide response under the `guide` key. + example: + guide: + activation_url_patterns: + - directive: allow + pathname: /dashboard/* + active: true + archived_at: null + channel_key: in-app-guide + created_at: "2024-01-01T00:00:00Z" + description: A guide to help users get started with the application + environment: development + key: getting-started + name: Getting Started Guide + semver: 0.0.1 + sha: "1234567890" + steps: + - name: Welcome to the App + ref: welcome-step + schema_key: tooltip + schema_semver: 1.0.0 + schema_variant_key: default + values: + text_field: value + target_audience_id: null + target_property_conditions: + all: + - argument: some_property + operator: equal_to + variable: recipient.property + type: banner + updated_at: "2024-01-01T00:00:00Z" + valid: true + properties: + guide: + $ref: '#/components/schemas/Guide' + required: + - guide + title: WrappedGuideResponse + type: object + x-struct: null + x-validate: null + description: OK + summary: Validate a guide + tags: + - Guides + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + const response = await client.guides.validate('guide_key', { + environment: 'development', + guide: { + channel_key: 'in-app-guide', + name: 'Getting Started Guide', + steps: [ + { + ref: 'welcome-step', + schema_key: 'tooltip', + schema_semver: '1.0.0', + schema_variant_key: 'default', + }, + ], + }, + }); + + console.log(response.guide); + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + response = client.guides.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [{ + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + }], + }, + ) + print(response.guide) + go: | + package main + + import ( + "context" + "fmt" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Guides.Validate( + context.TODO(), + "guide_key", + knockmapi.GuideValidateParams{ + Environment: "development", + Guide: knockmapi.GuideValidateParamsGuide{ + ChannelKey: "in-app-guide", + Name: "Getting Started Guide", + Steps: []knockmapi.GuideStepParam{{ + Ref: "welcome-step", + SchemaKey: "tooltip", + SchemaSemver: "1.0.0", + SchemaVariantKey: "default", + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Guide) + } + /v1/channel_groups/{channel_group_key}: + delete: + callbacks: {} + description: Archives (soft deletes) a channel group by key. + operationId: deleteChannelGroup + parameters: + - description: The key of the channel group to delete. + in: path + name: channel_group_key + required: true + schema: + type: string + x-struct: null + x-validate: null + responses: + "204": + content: + application/json: {} + description: No Content + summary: Delete a channel group + tags: + - Channel Groups + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + await client.channelGroups.delete('channel_group_key'); + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + client.channel_groups.delete( + "channel_group_key", + ) + go: | + package main + + import ( + "context" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + err := client.ChannelGroups.Delete(context.TODO(), "channel_group_key") + if err != nil { + panic(err.Error()) + } + } + get: + callbacks: {} + description: Get a channel group by its key. + operationId: getChannelGroup + parameters: + - description: The key of the channel group to retrieve. + in: path + name: channel_group_key + required: true + schema: + type: string + x-struct: null + x-validate: null + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ChannelGroup' + description: OK + summary: Get a channel group tags: - - Commits + - Channel Groups x-stainless-snippets: typescript: |- import KnockMgmt from '@knocklabs/mgmt'; @@ -12547,9 +14151,9 @@ paths: serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted }); - const response = await client.commits.promoteOne('id'); + const channelGroup = await client.channelGroups.retrieve('channel_group_key'); - console.log(response.commit); + console.log(channelGroup.channel_rules); python: |- import os from knock_mapi import KnockMgmt @@ -12557,63 +14161,41 @@ paths: client = KnockMgmt( service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted ) - response = client.commits.promote_one( - "id", + channel_group = client.channel_groups.retrieve( + "channel_group_key", ) - print(response.commit) + print(channel_group.channel_rules) go: | package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Commits.PromoteOne(context.TODO(), "id") - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Commit) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + channelGroup, err := client.ChannelGroups.Get(context.TODO(), "channel_group_key") + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", channelGroup.ChannelRules) } - /v1/guides/{guide_key}/validate: put: callbacks: {} - description: | - Validates a guide payload without persisting it. - - Note: Validating a guide is only done in the development environment context. - operationId: validateGuide + description: Creates or updates a channel group by key. + operationId: upsertChannelGroup parameters: - - description: The key of the guide. + - description: The key of the channel group to upsert. in: path - name: guide_key - required: true - schema: - type: string - x-struct: null - x-validate: null - - description: The environment slug. - in: query - name: environment + name: channel_group_key required: true schema: - example: development - type: string - x-struct: null - x-validate: null - - description: The slug of a branch to use. This option can only be used when `environment` is `"development"`. - in: query - name: branch - required: false - schema: - example: feature-branch type: string x-struct: null x-validate: null @@ -12621,35 +14203,22 @@ paths: content: application/json: schema: - description: Wraps the GuideRequest request under the guide key. + description: Wraps the ChannelGroupRequest request under the channel_group key. example: - guide: - activation_url_patterns: - - directive: allow - pathname: /dashboard/* - channel_key: in-app-guide - description: A guide to help users get started with the application - name: Getting Started Guide - steps: - - name: Welcome to the App - ref: welcome-step - schema_key: tooltip - schema_semver: 1.0.0 - schema_variant_key: default - values: - text_field: value - target_audience_id: null - target_property_conditions: - all: - - argument: some_property - operator: equal_to - variable: recipient.property + channel_group: + channel_rules: + - channel_key: push-fcm + index: 0 + rule_type: always + channel_type: push + name: Push Notification Group + operator: any properties: - guide: - $ref: '#/components/schemas/GuideRequest' + channel_group: + $ref: '#/components/schemas/ChannelGroupRequest' required: - - guide - title: WrappedGuideRequestRequest + - channel_group + title: WrappedChannelGroupRequestRequest type: object x-struct: null x-validate: null @@ -12660,52 +14229,44 @@ paths: content: application/json: schema: - description: Wraps the Guide response under the `guide` key. + description: Wraps the ChannelGroup response under the `channel_group` key. example: - guide: - activation_url_patterns: - - directive: allow - pathname: /dashboard/* - active: true - archived_at: null - channel_key: in-app-guide - created_at: "2024-01-01T00:00:00Z" - description: A guide to help users get started with the application - environment: development - key: getting-started - name: Getting Started Guide - semver: 0.0.1 - sha: "1234567890" - steps: - - name: Welcome to the App - ref: welcome-step - schema_key: tooltip - schema_semver: 1.0.0 - schema_variant_key: default - values: - text_field: value - target_audience_id: null - target_property_conditions: - all: - - argument: some_property - operator: equal_to - variable: recipient.property - type: banner - updated_at: "2024-01-01T00:00:00Z" - valid: true + channel_group: + channel_rules: + - channel: + archived_at: null + created_at: "2021-01-01T00:00:00Z" + custom_icon_url: null + id: 01234567-89ab-cdef-0123-456789abcdef + key: my-sendgrid-channel + name: My Sendgrid Channel + provider: sendgrid + type: email + updated_at: "2021-01-01T00:00:00Z" + created_at: "2021-01-01T00:00:00Z" + index: 0 + rule_type: always + updated_at: "2021-01-01T00:00:00Z" + channel_type: push + created_at: "2021-01-01T00:00:00Z" + key: push-group + name: Push Notification Group + operator: any + source: user + updated_at: "2021-01-01T00:00:00Z" properties: - guide: - $ref: '#/components/schemas/Guide' + channel_group: + $ref: '#/components/schemas/ChannelGroup' required: - - guide - title: WrappedGuideResponse + - channel_group + title: WrappedChannelGroupResponse type: object x-struct: null x-validate: null description: OK - summary: Validate a guide + summary: Upsert a channel group tags: - - Guides + - Channel Groups x-stainless-snippets: typescript: |- import KnockMgmt from '@knocklabs/mgmt'; @@ -12714,23 +14275,11 @@ paths: serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted }); - const response = await client.guides.validate('guide_key', { - environment: 'development', - guide: { - channel_key: 'in-app-guide', - name: 'Getting Started Guide', - steps: [ - { - ref: 'welcome-step', - schema_key: 'tooltip', - schema_semver: '1.0.0', - schema_variant_key: 'default', - }, - ], - }, + const response = await client.channelGroups.upsert('channel_group_key', { + channel_group: { channel_type: 'push', name: 'Push Notification Group' }, }); - console.log(response.guide); + console.log(response.channel_group); python: |- import os from knock_mapi import KnockMgmt @@ -12738,57 +14287,43 @@ paths: client = KnockMgmt( service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted ) - response = client.guides.validate( - guide_key="guide_key", - environment="development", - guide={ - "channel_key": "in-app-guide", - "name": "Getting Started Guide", - "steps": [{ - "ref": "welcome-step", - "schema_key": "tooltip", - "schema_semver": "1.0.0", - "schema_variant_key": "default", - }], + response = client.channel_groups.upsert( + channel_group_key="channel_group_key", + channel_group={ + "channel_type": "push", + "name": "Push Notification Group", }, ) - print(response.guide) + print(response.channel_group) go: | package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Guides.Validate( - context.TODO(), - "guide_key", - knockmapi.GuideValidateParams{ - Environment: "development", - Guide: knockmapi.GuideValidateParamsGuide{ - ChannelKey: "in-app-guide", - Name: "Getting Started Guide", - Steps: []knockmapi.GuideStepParam{knockmapi.GuideStepParam{ - Ref: "welcome-step", - SchemaKey: "tooltip", - SchemaSemver: "1.0.0", - SchemaVariantKey: "default", - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Guide) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.ChannelGroups.Upsert( + context.TODO(), + "channel_group_key", + knockmapi.ChannelGroupUpsertParams{ + ChannelGroup: knockmapi.ChannelGroupUpsertParamsChannelGroup{ + ChannelType: "push", + Name: "Push Notification Group", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.ChannelGroup) } /v1/message_types/{message_type_key}: get: @@ -12876,28 +14411,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - messageType, err := client.MessageTypes.Get( - context.TODO(), - "email", - knockmapi.MessageTypeGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", messageType.Valid) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + messageType, err := client.MessageTypes.Get( + context.TODO(), + "email", + knockmapi.MessageTypeGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", messageType.Valid) } put: callbacks: {} @@ -13077,33 +14612,33 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.MessageTypes.Upsert( - context.TODO(), - "email", - knockmapi.MessageTypeUpsertParams{ - Environment: "development", - MessageType: knockmapi.MessageTypeUpsertParamsMessageType{ - Description: knockmapi.String("This is a message type"), - Name: "My Message Type", - Preview: "
Hello, world!
", - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.MessageType) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.MessageTypes.Upsert( + context.TODO(), + "email", + knockmapi.MessageTypeUpsertParams{ + Environment: "development", + MessageType: knockmapi.MessageTypeUpsertParamsMessageType{ + Description: knockmapi.String("This is a message type"), + Name: "My Message Type", + Preview: "
Hello, world!
", + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.MessageType) } /v1/workflows/{workflow_key}: get: @@ -13190,28 +14725,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - workflow, err := client.Workflows.Get( - context.TODO(), - "workflow_key", - knockmapi.WorkflowGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", workflow.Valid) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + workflow, err := client.Workflows.Get( + context.TODO(), + "workflow_key", + knockmapi.WorkflowGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", workflow.Valid) } put: callbacks: {} @@ -13420,40 +14955,40 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Workflows.Upsert( - context.TODO(), - "workflow_key", - knockmapi.WorkflowUpsertParams{ - Environment: "development", - Workflow: knockmapi.WorkflowUpsertParamsWorkflow{ - Name: "My Workflow", - Steps: []knockmapi.WorkflowStepUnionParam{knockmapi.WorkflowStepUnionParam{ - OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ - Ref: "channel_1", - Template: knockmapi.InAppFeedTemplateParam{ - MarkdownBody: "Hello **{{ recipient.name }}**", - }, - Type: knockmapi.WorkflowInAppFeedStepTypeChannel, - }, - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Workflow) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Workflows.Upsert( + context.TODO(), + "workflow_key", + knockmapi.WorkflowUpsertParams{ + Environment: "development", + Workflow: knockmapi.WorkflowUpsertParamsWorkflow{ + Name: "My Workflow", + Steps: []knockmapi.WorkflowStepUnionParam{{ + OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ + Ref: "channel_1", + Template: knockmapi.InAppFeedTemplateParam{ + MarkdownBody: "Hello **{{ recipient.name }}**", + }, + Type: knockmapi.WorkflowInAppFeedStepTypeChannel, + }, + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Workflow) } /v1/branches/{branch_slug}: delete: @@ -13509,26 +15044,26 @@ paths: package main import ( - "context" + "context" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - err := client.Branches.Delete( - context.TODO(), - "feature-branch", - knockmapi.BranchDeleteParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + err := client.Branches.Delete( + context.TODO(), + "feature-branch", + knockmapi.BranchDeleteParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } } get: callbacks: {} @@ -13590,28 +15125,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - branch, err := client.Branches.Get( - context.TODO(), - "feature-branch", - knockmapi.BranchGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", branch.CreatedAt) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + branch, err := client.Branches.Get( + context.TODO(), + "feature-branch", + knockmapi.BranchGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", branch.CreatedAt) } post: callbacks: {} @@ -13673,28 +15208,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - branch, err := client.Branches.New( - context.TODO(), - "feature-branch", - knockmapi.BranchNewParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", branch.CreatedAt) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + branch, err := client.Branches.New( + context.TODO(), + "feature-branch", + knockmapi.BranchNewParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", branch.CreatedAt) } /v1/commits/promote: put: @@ -13816,24 +15351,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Commits.PromoteAll(context.TODO(), knockmapi.CommitPromoteAllParams{ - ToEnvironment: "to_environment", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Result) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Commits.PromoteAll(context.TODO(), knockmapi.CommitPromoteAllParams{ + ToEnvironment: "to_environment", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Result) } /v1/commits: get: @@ -14005,24 +15540,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.Commits.List(context.TODO(), knockmapi.CommitListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Commits.List(context.TODO(), knockmapi.CommitListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } put: callbacks: {} @@ -14148,24 +15683,158 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" + + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" + ) + + func main() { + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Commits.CommitAll(context.TODO(), knockmapi.CommitCommitAllParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Result) + } + /v1/members: + get: + callbacks: {} + description: Returns a paginated list of members for the current account. Optionally filter by role. + operationId: listMembers + parameters: + - description: 'Filter members by role. One of: owner, admin, member, production_only_member, billing, support.' + in: query + name: role + required: false + schema: + type: string + x-struct: null + x-validate: null + - description: Filter members by email address (exact match). + in: query + name: email + required: false + schema: + type: string + x-struct: null + x-validate: null + - description: The cursor to fetch entries after. + in: query + name: after + required: false + schema: + type: string + x-struct: null + x-validate: null + - description: The cursor to fetch entries before. + in: query + name: before + required: false + schema: + type: string + x-struct: null + x-validate: null + - description: The number of entries to fetch per-page. + in: query + name: limit + required: false + schema: + type: integer + x-struct: null + x-validate: null + responses: + "200": + content: + application/json: + schema: + description: A paginated list of Member. Contains a list of entries and page information. + example: + entries: + - created_at: "2024-01-15T10:30:00Z" + id: d4b8e8e0-1234-5678-9abc-def012345678 + role: admin + updated_at: "2024-06-20T14:45:00Z" + user: + avatar_url: https://www.gravatar.com/avatar/abc123 + created_at: "2024-01-10T08:00:00Z" + email: jane@example.com + id: a1b2c3d4-5678-9abc-def0-123456789abc + name: Jane Doe + updated_at: "2024-06-18T12:00:00Z" + page_info: + after: null + before: null + page_size: 25 + properties: + entries: + description: A list of entries. + items: + $ref: '#/components/schemas/Member' + nullable: false + type: array + x-struct: null + x-validate: null + page_info: + $ref: '#/components/schemas/PageInfo' + required: + - entries + - page_info + title: PaginatedMemberResponse + type: object + x-struct: null + x-validate: null + description: OK + summary: List members + tags: + - Members + x-stainless-snippets: + typescript: |- + import KnockMgmt from '@knocklabs/mgmt'; + + const client = new KnockMgmt({ + serviceToken: process.env['KNOCK_SERVICE_TOKEN'], // This is the default and can be omitted + }); + + // Automatically fetches more pages as needed. + for await (const member of client.members.list()) { + console.log(member.id); + } + python: |- + import os + from knock_mapi import KnockMgmt + + client = KnockMgmt( + service_token=os.environ.get("KNOCK_SERVICE_TOKEN"), # This is the default and can be omitted + ) + page = client.members.list() + page = page.entries[0] + print(page.id) + go: | + package main + + import ( + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Commits.CommitAll(context.TODO(), knockmapi.CommitCommitAllParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Result) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.Members.List(context.TODO(), knockmapi.MemberListParams{}) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/api_keys/exchange: post: @@ -14232,24 +15901,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.APIKeys.Exchange(context.TODO(), knockmapi.APIKeyExchangeParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.APIKey) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.APIKeys.Exchange(context.TODO(), knockmapi.APIKeyExchangeParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.APIKey) } /v1/broadcasts/{broadcast_key}: get: @@ -14336,28 +16005,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - broadcast, err := client.Broadcasts.Get( - context.TODO(), - "broadcast_key", - knockmapi.BroadcastGetParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", broadcast.Valid) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + broadcast, err := client.Broadcasts.Get( + context.TODO(), + "broadcast_key", + knockmapi.BroadcastGetParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", broadcast.Valid) } put: callbacks: {} @@ -14530,40 +16199,40 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Broadcasts.Upsert( - context.TODO(), - "broadcast_key", - knockmapi.BroadcastUpsertParams{ - Environment: "development", - Broadcast: knockmapi.BroadcastRequestParam{ - Name: "My Broadcast", - Steps: []knockmapi.BroadcastRequestStepUnionParam{knockmapi.BroadcastRequestStepUnionParam{ - OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ - Ref: "channel_1", - Template: knockmapi.InAppFeedTemplateParam{ - MarkdownBody: "Hello **{{ recipient.name }}**", - }, - Type: knockmapi.WorkflowInAppFeedStepTypeChannel, - }, - }}, - }, - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Broadcast) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Broadcasts.Upsert( + context.TODO(), + "broadcast_key", + knockmapi.BroadcastUpsertParams{ + Environment: "development", + Broadcast: knockmapi.BroadcastRequestParam{ + Name: "My Broadcast", + Steps: []knockmapi.BroadcastRequestStepUnionParam{{ + OfWorkflowInAppFeedStep: &knockmapi.WorkflowInAppFeedStepParam{ + Ref: "channel_1", + Template: knockmapi.InAppFeedTemplateParam{ + MarkdownBody: "Hello **{{ recipient.name }}**", + }, + Type: knockmapi.WorkflowInAppFeedStepTypeChannel, + }, + }}, + }, + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Broadcast) } /v1/message_types: get: @@ -14717,24 +16386,24 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - page, err := client.MessageTypes.List(context.TODO(), knockmapi.MessageTypeListParams{ - Environment: "development", - }) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", page) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + page, err := client.MessageTypes.List(context.TODO(), knockmapi.MessageTypeListParams{ + Environment: "development", + }) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", page) } /v1/broadcasts/{broadcast_key}/cancel: put: @@ -14844,28 +16513,28 @@ paths: package main import ( - "context" - "fmt" + "context" + "fmt" - "github.com/knocklabs/knock-mgmt-go" - "github.com/knocklabs/knock-mgmt-go/option" + "github.com/knocklabs/knock-mgmt-go" + "github.com/knocklabs/knock-mgmt-go/option" ) func main() { - client := knockmapi.NewClient( - option.WithServiceToken("My Service Token"), - ) - response, err := client.Broadcasts.Cancel( - context.TODO(), - "broadcast_key", - knockmapi.BroadcastCancelParams{ - Environment: "development", - }, - ) - if err != nil { - panic(err.Error()) - } - fmt.Printf("%+v\n", response.Broadcast) + client := knockmapi.NewClient( + option.WithServiceToken("My Service Token"), + ) + response, err := client.Broadcasts.Cancel( + context.TODO(), + "broadcast_key", + knockmapi.BroadcastCancelParams{ + Environment: "development", + }, + ) + if err != nil { + panic(err.Error()) + } + fmt.Printf("%+v\n", response.Broadcast) } security: - BearerAuth: [] diff --git a/data/specs/mapi/stainless.yml b/data/specs/mapi/stainless.yml index 5265c7f0c..de8de2b32 100644 --- a/data/specs/mapi/stainless.yml +++ b/data/specs/mapi/stainless.yml @@ -9,7 +9,8 @@ targets: package_name: "@knocklabs/mgmt" production_repo: knocklabs/knock-mgmt-node publish: - npm: true + npm: + auth_method: oidc python: package_name: knock_mapi production_repo: knocklabs/knock-mgmt-python @@ -100,6 +101,11 @@ resources: workflow_fetch_step: "#/components/schemas/WorkflowFetchStep" workflow_throttle_step: "#/components/schemas/WorkflowThrottleStep" workflow_trigger_workflow_step: "#/components/schemas/WorkflowTriggerWorkflowStep" + workflow_random_cohort_step: "#/components/schemas/WorkflowRandomCohortStep" + workflow_update_data_step: "#/components/schemas/WorkflowUpdateDataStep" + workflow_update_user_step: "#/components/schemas/WorkflowUpdateUserStep" + workflow_update_tenant_step: "#/components/schemas/WorkflowUpdateTenantStep" + workflow_update_object_step: "#/components/schemas/WorkflowUpdateObjectStep" methods: list: endpoint: get /v1/workflows @@ -144,6 +150,12 @@ resources: channel_group_rule: "#/components/schemas/ChannelGroupRule" methods: list: get /v1/channel_groups + retrieve: + endpoint: get /v1/channel_groups/{channel_group_key} + upsert: + endpoint: put /v1/channel_groups/{channel_group_key} + delete: + endpoint: delete /v1/channel_groups/{channel_group_key} channels: models: channel: "#/components/schemas/Channel" @@ -154,6 +166,14 @@ resources: in_app_feed_channel_settings: "#/components/schemas/InAppFeedChannelSettings" methods: list: get /v1/channels + members: + models: + member: "#/components/schemas/Member" + member_user: "#/components/schemas/MemberUser" + methods: + list: get /v1/members + retrieve: get /v1/members/{id} + delete: delete /v1/members/{id} environments: models: environment: "#/components/schemas/Environment" From eab0c7574504db25a55079757e88d024887ac495 Mon Sep 17 00:00:00 2001 From: Matt Kufchak Date: Wed, 25 Feb 2026 17:50:52 -0600 Subject: [PATCH 04/96] chore(kno-11675): Clarify workflow execution behavior (#1314) * docs: clarify workflow behavior when channel steps fail vs skip - Add new 'Understanding workflow execution behavior' section to debugging-workflows.mdx explaining: - Channel step failures halt workflow after 3 retry attempts (e.g., template rendering errors, invalid config) - Channel step skips allow workflow to continue (conditions not met, missing config, preference opt-outs, missing recipient data) - Update channel-step.mdx to document step failure behavior during execution - Add warning callout to testing-and-debugging.mdx about template errors halting workflows Resolves KNO-11675 Co-authored-by: Matt Kufchak * style: fix Prettier formatting issues Co-authored-by: Matt Kufchak * fix: remove send windows from skipped step causes Send windows delay notifications but don't cause steps to be skipped. Co-authored-by: Matt Kufchak * mk updates * additional updates * suggested change Co-authored-by: Scoti Dodson * apply review suggestion * feedback --------- Co-authored-by: Cursor Agent Co-authored-by: Scoti Dodson --- content/designing-workflows/channel-step.mdx | 2 + .../debugging-workflows.mdx | 39 ++++++++++++++++++- .../template-editor/testing-and-debugging.mdx | 23 ++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/content/designing-workflows/channel-step.mdx b/content/designing-workflows/channel-step.mdx index 45ec06f0c..2217ec415 100644 --- a/content/designing-workflows/channel-step.mdx +++ b/content/designing-workflows/channel-step.mdx @@ -20,6 +20,8 @@ When a channel step is executed Knock does the following: If the step continues, Knock will render [the template](/template-editor) associated with the step and enqueue a message to [deliver to the provider](/send-notifications/delivering-notifications) via the configured credentials on the channel. +See our [debugging workflows documentation](/send-notifications/debugging-workflows#understanding-workflow-execution-behavior) for more details on how workflow steps are executed and what happens when they encounter errors. + ## Channel support You can read more about configuring channels in our [integrations overview](/integrations/overview). diff --git a/content/send-notifications/debugging-workflows.mdx b/content/send-notifications/debugging-workflows.mdx index 88e5ac5d3..9ad29736f 100644 --- a/content/send-notifications/debugging-workflows.mdx +++ b/content/send-notifications/debugging-workflows.mdx @@ -45,10 +45,45 @@ You can see a video of our workflow debugger in action here: } /> -You can access the workflow debugger from our "Logs" page, which you'll find in the left hand environment sidebar in the dashboard. From there: +You can access the workflow debugger from the "Runs" tab on a given workflow or the "Workflow runs" tab on a recipient record. + +You can also access it from our "Logs" page, which you'll find in the left-hand sidebar in the dashboard. From there: 1. Find an API log that triggered a workflow run (**hint**: you can use the filters to find only workflow API requests) 2. In the right hand panel, click the "Workflow runs" tab 3. Select a workflow run for any recipient to view the debugger -**Note**: you can also use the debugger to look at test runs as well. + + +## Understanding workflow execution behavior + +When a workflow runs, each step is executed in sequence. Sometimes an individual step is skipped or encounters an error, and it's important to understand how this affects the workflow run as a whole. + +### When a workflow step is skipped + +There are several controlled scenarios where a step is skipped and the workflow run continues to execute subsequent steps. + +Steps are skipped when: + +- **Step conditions are not met.** If a step has [conditions](/designing-workflows/step-conditions) configured and they evaluate to false, the step is skipped. +- **Channel configuration is missing.** If the channel associated with a step has not been configured in the current environment, the step is skipped. +- **Recipient preferences opt out.** If the recipient has set [preferences](/preferences/overview) that opt them out of this notification type or channel, the step is skipped. +- **Recipient is missing required data.** If the recipient lacks the data required for delivery on this channel (for example, no `email` address for an email step, or no [channel data](/managing-recipients/setting-channel-data) for a push step), the step is skipped. +- **A dynamic [batch](/designing-workflows/batch-function), [delay](/designing-workflows/delay-function), or [throttle](/designing-workflows/throttle-function) step encounters an invalid window value.** If a workflow step encounters a missing or invalid dynamic window value (like a timestamp in the past), the step is skipped. + +The workflow debugger will indicate when a step has been skipped and provide the reason why. This can help you understand why a recipient did not receive a notification on a particular channel, or why a workflow function was not processed as expected. + +### When a workflow step fails + +When a workflow step encounters an error during execution (such as a template rendering error or an error response from a [fetch](/designing-workflows/fetch-function) step), Knock will retry the step **up to 3 total times**. If all retry attempts fail, the step is marked as failed and **the workflow run is halted.** No subsequent steps will execute. + +Common causes of workflow step failures include: + +- **Template rendering errors.** Invalid Liquid syntax or missing required variables that prevent the message template from rendering. +- **Fetch step errors.** Errors or timeouts from the HTTP request made by the fetch step. + +You can identify failed steps in the workflow debugger by looking for error states on individual steps. The debugger will show you the error details to help diagnose and fix the issue. diff --git a/content/template-editor/testing-and-debugging.mdx b/content/template-editor/testing-and-debugging.mdx index 2e3d8683d..3cd7180b5 100644 --- a/content/template-editor/testing-and-debugging.mdx +++ b/content/template-editor/testing-and-debugging.mdx @@ -35,7 +35,28 @@ You can send a test message by clicking the "Run a test" button in the top right ## Debugging template errors -If Knock cannot render your template, you'll see an error message in the preview pane. Most commonly, you'll see this error when you've got invalid liquid syntax in your template that's preventing the template from being rendered. +If Knock cannot render your template, you'll see an error message in the preview pane. Most commonly, you'll see this error when you've got invalid Liquid syntax in your template that's preventing the template from being rendered. + + + When a template fails to render during a workflow run (typically due to + missing or malformed trigger data values), Knock will retry + the step up to 3 times. If all attempts fail, the entire workflow run is + halted. See our{" "} + + debugging workflows documentation + {" "} + for more details. +
+
+ You can help avoid this issue by leveraging our trigger data validation feature. + + +} +/> ## Frequently asked questions From a1d17b4d7cc5fd57ba80ecf82060c64e700cc965 Mon Sep 17 00:00:00 2001 From: Matt Kufchak Date: Fri, 27 Feb 2026 10:28:36 -0600 Subject: [PATCH 05/96] chore(kno-11841): inline attachments docs for Resend (#1326) * Add Resend to list of providers supporting inline attachments Co-authored-by: Matt Kufchak * Fix formatting with Prettier Co-authored-by: Matt Kufchak * add resend to guidance for inline image attachments --------- Co-authored-by: Cursor Agent --- content/integrations/email/attachments.mdx | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/content/integrations/email/attachments.mdx b/content/integrations/email/attachments.mdx index 53d0f546a..5d01758df 100644 --- a/content/integrations/email/attachments.mdx +++ b/content/integrations/email/attachments.mdx @@ -15,13 +15,13 @@ layout: integrations Every attachment you send to Knock in your `data` payload should include the following properties (those marked with an `*` are required): -| Property | Description | -| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `name`\* | The name of the file | -| `content_type`\* | A mime type for the file | -| `content`\* | The base64 encoded file content (up to 10mb) | -| `content_id` | An optional unique `Content-ID` for the attachment. Currently only supported for [SendGrid](/integrations/email/sendgrid) and [Postmark](/integrations/email/postmark). See Referencing attachment files inline for more details. | -| `disposition` | An optional disposition for the attachment (`inline` or `attachment`). Currently only supported for [SendGrid](/integrations/email/sendgrid) and [Postmark](/integrations/email/postmark). | +| Property | Description | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name`\* | The name of the file | +| `content_type`\* | A mime type for the file | +| `content`\* | The base64 encoded file content (up to 10mb) | +| `content_id` | An optional unique `Content-ID` for the attachment. Currently only supported for SendGrid, Postmark, and Resend. See Referencing attachment files inline for more details. | +| `disposition` | An optional disposition for the attachment (`inline` or `attachment`). Currently only supported for SendGrid and Postmark. |
```js title="An example attachment object" @@ -74,10 +74,23 @@ filesAndRecipients.forEach(({ id, file }) => { ## Referencing attachment files inline -If you're using [SendGrid](/integrations/email/sendgrid) or [Postmark](/integrations/email/postmark) as your email provider, you can set attachment files to be inline in your email template by providing a `disposition` property of `inline` on the attachment object you send in your trigger call. +If you're using [SendGrid](/integrations/email/sendgrid) or [Postmark](/integrations/email/postmark) as your email provider, you can set attachment files to be inline in your email messages by providing a `disposition` property of `inline` on the attachment object you send in your trigger call. + +[Resend](/integrations/email/resend) supports inline images (see below), but does not allow you to explicitly set the disposition of an attachment. ### Inline image attachments + + When using Resend, images can be referenced inline without setting a{" "} + disposition property on the attachment object. + + } +/> + To attach image files to your email and reference them inline, add a `content_id` and `disposition` to the attachment object. You can then reference the attachment in your template using the `cid:` prefix and the `content_id` value. ```js title="An example inline image attachment" From 7ad95b442674aa87be2a69dc8b42be27a0dce412 Mon Sep 17 00:00:00 2001 From: Sam Seely Date: Sat, 28 Feb 2026 10:32:44 -0500 Subject: [PATCH 06/96] docs(hightouch): update audience sync docs to reflect automatic creation (#1327) Remove the prerequisite requiring manual audience creation in Knock, since the integration now auto-creates a static audience if the key doesn't exist. Update the "Add the audience key" step description accordingly and remove the outdated screenshot. Co-authored-by: Claude Sonnet 4.6 --- content/integrations/sources/hightouch.mdx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/content/integrations/sources/hightouch.mdx b/content/integrations/sources/hightouch.mdx index 51916de85..5605c014d 100644 --- a/content/integrations/sources/hightouch.mdx +++ b/content/integrations/sources/hightouch.mdx @@ -82,8 +82,7 @@ Hightouch models can be synced to Knock [audiences](/concepts/audiences) by conf ### Prerequisites 1. Determine which Knock environment you want to sync your audience to. You most likely want to sync in the Production environment, unless you’re configuring a test sync. -2. Create an audience in Knock that will serve as the target for your sync. -3. Have your Knock environment’s secret API key ready. Each environment has its own unique set of API keys; you can find your secret API key in your dashboard under **Platform** > **API keys**. Be sure that the correct environment is selected in the switcher at the top of the page. +2. Have your Knock environment’s secret API key ready. Each environment has its own unique set of API keys; you can find your secret API key in your dashboard under **Platform** > **API keys**. Be sure that the correct environment is selected in the switcher at the top of the page. ### Configure Knock as a Hightouch Destination @@ -231,15 +230,7 @@ Once you have configured Knock as an Embedded Destination in Hightouch, you can - Next, add the key of the Knock audience that you want to sync to. Click "Continue." - - Add the audience key + Next, enter the key of the Knock audience you want to sync to. If an audience with this key doesn't exist in Knock yet, it will be created automatically when the sync runs for the first time. Click "Continue." From e03fbbd019ad9cda9227c3cd2c60d3304a5b201a Mon Sep 17 00:00:00 2001 From: Sam Seely Date: Mon, 2 Mar 2026 22:25:57 -0500 Subject: [PATCH 07/96] docs: add skills documentation (#1330) * feat: add skill docs * chore: remove beta tag from MCP server sidebar item Co-Authored-By: Claude Sonnet 4.6 * chore: remove beta callout from MCP server page Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- .../developer-tools/building-with-llms.mdx | 6 +++ content/developer-tools/knock-cli.mdx | 12 +++++ content/developer-tools/mcp-server.mdx | 12 ----- content/developer-tools/skills.mdx | 44 +++++++++++++++++++ data/sidebars/developerToolsSidebar.ts | 7 +-- 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 content/developer-tools/skills.mdx diff --git a/content/developer-tools/building-with-llms.mdx b/content/developer-tools/building-with-llms.mdx index 09991ecb1..e1742fd97 100644 --- a/content/developer-tools/building-with-llms.mdx +++ b/content/developer-tools/building-with-llms.mdx @@ -20,6 +20,12 @@ You can use the Knock MCP server to aid in building your Knock integration, and Learn more in our [MCP Server](/developer-tools/mcp-server) docs. +## Skills + +Skills are packaged instructions and rules that extend AI agent capabilities with Knock-specific knowledge. Install a skill once and your agent automatically applies the right patterns when working on Knock-related tasks. + +Learn more in our [Skills](/developer-tools/skills) docs. + ## Knock Agent Toolkit SDK We provide an Agent Toolkit that allows you to integrate Knock via function calling to AI agent workflows. Using Agent Toolkit gives your AI agents the ability to send cross-channel messaging to your customers, as well as powering human-in-the-loop interactions. diff --git a/content/developer-tools/knock-cli.mdx b/content/developer-tools/knock-cli.mdx index 636f11259..521240460 100644 --- a/content/developer-tools/knock-cli.mdx +++ b/content/developer-tools/knock-cli.mdx @@ -62,3 +62,15 @@ Once set, the Knock CLI will use the `knockDir` property for all push and pull c ## CLI reference You can find a complete reference for all of the commands and flags available on the [CLI in our comprehensive reference](/cli/overview). + +## Using the CLI with AI coding agents + +The `knock-cli` skill packages the CLI docs and patterns into a set of rules that AI agents—such as Cursor and Claude Code—can use to pull, push, and manage Knock resources directly from your editor. + +Install the skill to enable your agent to work with workflows, templates, guides, and partials without needing manual prompting: + +```bash +npx skills add knocklabs/skills --skill knock-cli +``` + +Learn more on the [Skills](/developer-tools/skills) page. diff --git a/content/developer-tools/mcp-server.mdx b/content/developer-tools/mcp-server.mdx index 9c7b4a69d..33d6bb906 100644 --- a/content/developer-tools/mcp-server.mdx +++ b/content/developer-tools/mcp-server.mdx @@ -4,18 +4,6 @@ description: Use the Knock MCP server to make Knock accessible to LLMs and AI ag section: Developer tools --- - - Note: the Knock MCP server is currently in beta. Due to - the non-deterministic nature of LLMs it's recommended that you test - running the MCP against resources in your development environment before - running it in production. - - } -/> - Knock ships a remote MCP server at `mcp.knock.app/mcp` that exposes the primitives of Knock to LLMs and AI via the Model Context Protocol (MCP) so that your AI agents can discover and use Knock via tool calling. Here are some examples of how you can use the MCP server in your workflow: diff --git a/content/developer-tools/skills.mdx b/content/developer-tools/skills.mdx new file mode 100644 index 000000000..f87cf732b --- /dev/null +++ b/content/developer-tools/skills.mdx @@ -0,0 +1,44 @@ +--- +title: Skills +description: Use Knock skills to give AI coding agents Knock-specific knowledge and patterns for managing notifications. +section: Developer tools +--- + +Skills are packaged instructions and rules for AI coding agents that extend their capabilities with Knock-specific knowledge. When you add a skill to your agent, it automatically activates when you ask it to work on related tasks—no manual prompting required. + +Knock publishes an open-source skills package on GitHub at github.com/knocklabs/skills. + +## Available skills + +### `knock-cli` + +The `knock-cli` skill teaches AI agents how to use the [Knock CLI](/developer-tools/knock-cli) to manage your Knock resources. Use it when you want an agent to: + +- Pull workflows, templates, guides, and partials to your local machine +- Push local changes back to Knock +- Manage Knock resources as part of a development or CI/CD workflow + +### `notification-best-practices` + +The `notification-best-practices` skill gives AI agents comprehensive guidelines for notification design and implementation. Use it when you want an agent to: + +- Write notification copy across channels (email, SMS, push, in-app) +- Apply best practices for transactional and welcome email templates +- Follow channel-specific formatting and content guidelines + +## Installation + +Install the entire skills package with a single command: + +```bash +npx skills add knocklabs/skills +``` + +Or install specific skills by passing a flag: + +```bash +npx skills add knocklabs/skills --skill knock-cli +npx skills add knocklabs/skills --skill notification-best-practices +``` + +Once installed, skills are automatically available to your agent and activated when relevant tasks are detected. diff --git a/data/sidebars/developerToolsSidebar.ts b/data/sidebars/developerToolsSidebar.ts index a469e345b..ae4118e66 100644 --- a/data/sidebars/developerToolsSidebar.ts +++ b/data/sidebars/developerToolsSidebar.ts @@ -70,11 +70,8 @@ export const DEVELOPER_TOOLS_SIDEBAR_CONTENT: SidebarContent[] = [ }, ], }, - { - slug: `${baseSlug}/mcp-server`, - title: "MCP server", - isBeta: true, - }, + { slug: `${baseSlug}/mcp-server`, title: "MCP server" }, + { slug: `${baseSlug}/skills`, title: "Skills" }, { slug: `${baseSlug}/building-with-llms`, title: "Building with LLMs", From 69fbad0d29cf45b3c409abba578f12a4c38206d1 Mon Sep 17 00:00:00 2001 From: Matt Kufchak Date: Tue, 3 Mar 2026 12:28:14 -0600 Subject: [PATCH 08/96] chore(kno-11406): clarify partials usage (#1290) * chore(kno-11406): clarify partials usage * format * format * fix liquid reference formatting bug flagged by bugbot * chore: add additional guidance on partial styles * chore: add FAQ on schema input defaults * add JSON input type * chore: add additional guidance on json inputs * fix: typo * chore: add json input to message types schema * reorganize json faq * change code styling for liquid highlights --- .../message-types/schema-reference.mdx | 50 +++++++ .../partials/html-partials.mdx | 28 +++- content/template-editor/partials/overview.mdx | 124 ++++++++++++------ .../partials/schema-reference.mdx | 89 ++++++++++++- .../reference-liquid-helpers.mdx | 8 +- 5 files changed, 255 insertions(+), 44 deletions(-) diff --git a/content/in-app-ui/message-types/schema-reference.mdx b/content/in-app-ui/message-types/schema-reference.mdx index e61c2abc5..5b44a8708 100644 --- a/content/in-app-ui/message-types/schema-reference.mdx +++ b/content/in-app-ui/message-types/schema-reference.mdx @@ -501,3 +501,53 @@ Every image field contains three subfields: } } ``` + +### JSON + +A JSON input field with schema validation. + +#### Settings + + + + + + + + +#### Example + +```json +{ + "type": "json", + "key": "data", + "label": "Data", + "settings": { + "description": "A description of the JSON field", + "required": true, + "default": { "key": "value" }, + "schema": { + "properties": { + "key": { "type": "string" } + }, + "required": ["key"] + } + } +} +``` diff --git a/content/template-editor/partials/html-partials.mdx b/content/template-editor/partials/html-partials.mdx index e10283a06..08bcedc37 100644 --- a/content/template-editor/partials/html-partials.mdx +++ b/content/template-editor/partials/html-partials.mdx @@ -64,9 +64,17 @@ You can create a schema for an HTML partial by clicking the "Edit schema" button Read more about the schema reference for HTML partials in the [Partial schema reference](/template-editor/partials/schema-reference) page. +## Editing HTML partial content + +HTML partials display a preview alongside the editor. Open the preview by clicking the "Preview" button or using the `Cmd + ]` keyboard shortcut on Mac, or `Ctrl + ]` on Windows. + +- Select an [email layout](/integrations/email/layouts) to preview the partial within. +- Use the ` + +

This is a partial CSS example.

``` -When I include this partial in an email template, either via a render tag or as a block in the visual editor, the CSS from this partial will be extracted and included within the `` of the compiled email template. Styles are deduplicated and are only included at-most once in the final email template. +When you include this partial in an email template, either via a render tag or as a block in the visual editor, the CSS from this partial will be extracted and included within the `` of the compiled email template. Styles are deduplicated and are only included at-most once in the final email template. diff --git a/content/template-editor/partials/overview.mdx b/content/template-editor/partials/overview.mdx index c85edb26c..845ccfc11 100644 --- a/content/template-editor/partials/overview.mdx +++ b/content/template-editor/partials/overview.mdx @@ -38,7 +38,7 @@ After creating a partial, you can edit its content in the code editor. You can include Liquid variables in your content which will be scoped to your partial. When using the partial in a template, you can pass in values for these variables. To include a variable in your partial, use the following syntax: `{{ variable_name }}`. @@ -53,14 +53,6 @@ You can include Liquid variables in your content which will be scoped to your pa } /> -#### Editing HTML partial content - -HTML partials display a preview alongside the editor. Open the preview by clicking the "Preview" button or using the `Cmd + ]` keyboard shortcut on Mac, or `Ctrl + ]` on Windows. - -- Select an [email layout](/integrations/email/layouts) to preview the partial within. -- Use the ` +``` + +#### Swapping logos and icons in dark mode + +If your logo or icon doesn't render well on a dark background, upload dark-mode versions in account branding and expose them via `vars.branding.dark_logo_url` and `vars.branding.dark_icon_url`. Render both images in your layout and toggle them with CSS: + +```html title="Rendering light and dark logos" +{% assign dark_logo_url = vars.branding.dark_logo_url | default: +vars.branding.logo_url %} + + + {{ vars.app_name }} + + {{ vars.app_name }} + + +``` -To set pre-content variables for your template, open the email template editor, click the three-dot menu in the top right corner and select "Manage template overrides." You'll add your pre-content variables to the pre-content field using liquid syntax. +Hide the dark image by default and swap them inside your dark mode media query: -You can use pre-content variables to: +```css title="CSS to toggle light and dark images" +.dark-img { + display: none; + visibility: hidden; +} + +@media (prefers-color-scheme: dark) { + .dark-img { + display: inline !important; + visibility: visible !important; + } -- Declare any template-specific liquid variables to control or dynamically alter parts of your email layout without needing to create separate email layouts. -- Declare any template-specific liquid variables for use _throughout_ your email template in a single, clear location. + .light-img { + display: none !important; + visibility: hidden !important; + } +} +``` + +The `