From 604eca0cbed27a36ac5a72f9cd7180c3eff5c358 Mon Sep 17 00:00:00 2001 From: Serhii Kozlovskyi Date: Thu, 6 Aug 2026 12:04:51 +0300 Subject: [PATCH 1/3] docs(developer): document the Workflow Step Type module comprehensively Significantly expand the workflow-step-type module documentation to cover the crowdin_agent authentication requirement, the agent user concept, the token flow, port semantics, string statuses, webhook delivery guarantees, settings lifecycle callbacks, a recommended implementation flow, limitations, and troubleshooting. Also: - document the crowdin_agent authentication type in the App Descriptor article and reference it from the Security article - describe the agent user and failed strings recovery in the App-based Workflow Step article Co-Authored-By: Claude Fable 5 --- .../developer/crowdin-apps/app-descriptor.mdx | 7 +- .../docs/developer/crowdin-apps/security.mdx | 6 + .../modules/other/workflow-step-type.mdx | 500 +++++++++++++++++- .../workflows/app-based-workflow-step.mdx | 16 +- 4 files changed, 505 insertions(+), 24 deletions(-) diff --git a/src/content/docs/developer/crowdin-apps/app-descriptor.mdx b/src/content/docs/developer/crowdin-apps/app-descriptor.mdx index ee83be640..4dcebf746 100644 --- a/src/content/docs/developer/crowdin-apps/app-descriptor.mdx +++ b/src/content/docs/developer/crowdin-apps/app-descriptor.mdx @@ -168,13 +168,16 @@ The app descriptor is a JSON object with the following structure: ## Authentication -Specifies the authentication type to use when signing requests from the host application to the Crowdin app. Crowdin Apps support two types of authentication: +Specifies the authentication type to use when signing requests from the host application to the Crowdin app. Crowdin Apps support the following types of authentication: * using OAuth app (`crowdin_app` value) * without OAuth app (`none` value) +* using a dedicated agent user (`crowdin_agent` value) – required by the [Workflow Step Type](/developer/crowdin-apps-module-workflow-step-type/#authentication) module In case your Crowdin app requires access to Crowdin API at any time, it’s recommended to use the `crowdin_app`, in other cases feel free to use the `none`. The authentication type `none` grants access to Crowdin API as well as the `crowdin_app`, but only when the Crowdin app is executed on the user side, for example, when the iframe opens. +The `crowdin_agent` type is used by apps that act as long-lived participants in projects (e.g., process strings on a custom workflow step). When such an app is installed, Crowdin creates a dedicated agent (bot) user, and the app's API calls are authenticated as that user. Read more about [agent authentication](/developer/crowdin-apps-module-workflow-step-type/#authentication). + Example: ```json title="manifest.json" @@ -199,7 +202,7 @@ Example:

Type: string

Defaults to: none

-

Allowed values: none, crowdin_app

+

Allowed values: none, crowdin_app, crowdin_agent

Description: The type of authentication to use.

diff --git a/src/content/docs/developer/crowdin-apps/security.mdx b/src/content/docs/developer/crowdin-apps/security.mdx index 643717d73..2a8fa617c 100644 --- a/src/content/docs/developer/crowdin-apps/security.mdx +++ b/src/content/docs/developer/crowdin-apps/security.mdx @@ -4,8 +4,14 @@ description: Ensure the high level of security for Crowdin apps slug: developer/crowdin-apps-security --- +import { Aside } from '@astrojs/starlight/components'; + To ensure the high level of security for cases when the Crowdin app works with the data from Crowdin (i.e. uses the authorization via `crowdin_app`), we've developed a security mechanism. The main principle of this security mechanism is based on the exchange of the JWT token between Crowdin and the Crowdin app. JWT token is signed with an OAuth Client Secret known only to the two final parties. This way, the Crowdin app can get a confirmation that the page is opened precisely in Crowdin. + + ## Implementation To implement the authorization and authentication in your Crowdin app, follow these steps: diff --git a/src/content/docs/developer/modules/other/workflow-step-type.mdx b/src/content/docs/developer/modules/other/workflow-step-type.mdx index a3c5bd726..02ed279b0 100644 --- a/src/content/docs/developer/modules/other/workflow-step-type.mdx +++ b/src/content/docs/developer/modules/other/workflow-step-type.mdx @@ -7,7 +7,183 @@ sidebar: badge: New --- -This module allows you to create custom workflow step types to extend the default list of workflow steps in Crowdin Enterprise. With this app installed, the new workflow steps type become available in the workflow editor, where they can be added to workflows and templates, enabling greater customization and flexibility. +import { Steps, Aside } from '@astrojs/starlight/components'; +import ReadMore from '~/components/ReadMore.astro'; + +This module allows you to create custom workflow step types to extend the default list of workflow steps in Crowdin Enterprise. With this app installed, the new workflow step types become available in the workflow editor, where they can be added to workflows and templates, enabling greater customization and flexibility. + +A custom workflow step acts as an external processing stage in a workflow: Crowdin Enterprise handles the routing of strings, status tracking, and progress counters, while your app implements the step's **condition of done** – the custom logic that decides when a string is considered complete on the step and which output it leaves through. Typical use cases include AI-based review, integration with an external review or MT system, compliance gates, or delay/scheduling steps. + +## How It Works + +The Workflow Step Type module follows an asynchronous, event-driven integration model: + + + 1. An organization admin installs the app. The custom step types provided by the app become available in the workflow editor. + 2. A project manager adds the custom step to a workflow or workflow template and configures it via the settings UI provided by the app. + 3. When strings reach the custom step, Crowdin Enterprise sends the `string.status_on_step.recalculation_triggered` webhook event to the app. + 4. The app evaluates its condition of done for the received strings. Processing is asynchronous and can take as long as needed. + 5. The app updates the status of each processed string via the API, assigning it to one of the step's declared output ports according to its routing logic. + 6. Crowdin Enterprise routes the strings to the next workflow step connected to that output. + + +## Requirements + +Apps that include the `workflow-step-type` module must meet all of the following requirements. An app descriptor that doesn't meet them will fail validation during installation: + +* **`crowdin_agent` authentication** – the app must use the `crowdin_agent` authentication type and declare an `agent` in the app descriptor. Other authentication types (e.g., `crowdin_app` or `none`) are not allowed for this module. Read more about [Authentication](#authentication). +* **Companion Webhook module** – the same app must also declare a [Webhook module](/developer/crowdin-apps-module-webhook/) subscribed to the `string.status_on_step.recalculation_triggered` event. Without it, the custom step cannot receive strings for processing. +* **App backend** – all module URLs are relative to the app's `baseUrl`, so the module is not compatible with [serverless apps](/developer/crowdin-apps-serverless/). +* **Crowdin Enterprise only** – custom workflow steps are available only in Crowdin Enterprise projects with workflows. + +## Authentication + +The `workflow-step-type` module requires the `crowdin_agent` authentication type. If the app descriptor uses any other authentication type (or omits the `authentication` object), the installation fails with the following error: + +> Only crowdin_agent authentication type is allowed for workflow-step-type module type + +### Why the Agent Authentication Type + +A custom workflow step is a long-lived participant in your projects rather than a UI extension. It processes strings asynchronously, triggered by webhooks, without any user session involved. To support this, Crowdin Enterprise creates a dedicated **agent** – a bot user that represents your app in the organization: + +* The agent user is created automatically when the app is installed and removed when the app is uninstalled. +* All API calls the app makes to process strings on the custom step are authenticated as the agent user. +* The agent must have manager access to every project where the custom step is used. A project manager invites the agent to the project as a manager as part of setting up the workflow step. Alternatively, the agent can be assigned as a manager to all existing projects during the app installation. +* All actions performed by the app are attributed to the agent user in the project activity, providing a clear audit trail. + +### Agent Declaration + +When using the `crowdin_agent` authentication type, the app descriptor must include a top-level `agent` object that describes the agent user: + +```json title="manifest.json" +{ + "authentication": { + "type": "crowdin_agent", + "clientId": "your-client-id" + }, + "agent": { + "name": "Custom Step", + "username": "custom-step-agent", + "avatarUrl": "/assets/agent-avatar.png" + } +} +``` + + + + + + + + + + + + + + + + +
agent.username +

Type: string

+

Required: yes

+

Description: The username for the agent user created in the organization.

+
agent.name +

Type: string

+

Required: no

+

Description: The display name of the agent user. If omitted, the app name is used.

+
agent.avatarUrl +

Type: string

+

Required: no

+

Description: The relative URL to the agent user's avatar. If omitted, the app logo is used.

+
+ +### Obtaining an API Token + +The token flow for `crowdin_agent` is similar to the [`crowdin_app` flow](/developer/crowdin-apps-installation/#installed-event-communication-flow). When the app is installed, Crowdin sends the [Installed event](/developer/crowdin-apps-app-descriptor/#installed-event-payload) to the app. For apps with the `crowdin_agent` authentication type, the Installed event payload additionally contains the `agentId` property – the numeric identifier of the agent user created for your app. + +To obtain an API access token, the app sends the following request: + +```shell +POST https://accounts.crowdin.com/oauth/token +``` + +**Token request parameters:** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
grant_type: crowdin_agent +

Type: string

+

Required: yes

+

Description: Specifies the token flow for an agent app.

+
client_id +

Type: string

+

Required: yes

+

Description: The Client ID for the app is received when the app is registered.

+
client_secret +

Type: string

+

Required: yes

+

Description: The Client Secret for the app is received when the app is registered.

+
app_id +

Type: string

+

Required: yes

+

Description: Crowdin app identifier from the app descriptor.

+
app_secret +

Type: string

+

Required: yes

+

Description: The unique secret used to authorize your Crowdin app. This value is retrieved from the Installed event.

+
domain +

Type: string

+

Required: yes

+

Description: The name of the organization the app is installed to. This value is retrieved from the Installed event.

+
user_id +

Type: integer

+

Required: yes

+

Description: The identifier of the user who installed the app. This value is retrieved from the Installed event.

+
agent_id +

Type: integer

+

Required: yes

+

Description: The identifier of the agent user created for your app. This value is retrieved from the Installed event (agentId property).

+
+ +The resulting access token is issued for the agent user. Use it in the `Authorization: Bearer` header for the [API methods](#api-methods) that manage string statuses on the custom step. + + ## Access @@ -19,8 +195,30 @@ You can grant access to this module to one of the following user categories: ## Structure +The example below shows a complete app descriptor for an app that provides a custom workflow step. Note the `crowdin_agent` authentication type, the `agent` object, and the companion `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event – all three are required: + ```json title="manifest.json" { + "identifier": "custom-workflow-step-app", + "name": "Custom Workflow Step App", + "description": "A sample app that provides a custom workflow step", + "logo": "/logo.png", + "baseUrl": "https://example.com", + "authentication": { + "type": "crowdin_agent", + "clientId": "your-client-id" + }, + "agent": { + "name": "Custom Step", + "username": "custom-step-agent", + "avatarUrl": "/assets/agent-avatar.png" + }, + "events": { + "installed": "/hooks/installed" + }, + "scopes": [ + "project" + ], "modules": { "workflow-step-type": [ { @@ -61,6 +259,15 @@ You can grant access to this module to one of the following user categories: "crowdin-enterprise" ] } + ], + "webhook": [ + { + "key": "workflow-step-webhook", + "url": "/hooks/workflow", + "events": [ + "string.status_on_step.recalculation_triggered" + ] + } ] } } @@ -83,15 +290,15 @@ You can grant access to this module to one of the following user categories:

Type: string

Required: yes

-

Description: The human-readable name of the module.

+

Description: The human-readable name of the workflow step type shown in the workflow editor.

logo

Type: string

-

Required: yes

-

Description: The relative URL to the custom AI's logo that will be displayed in the Crowdin Enterprise UI.
+

Required: no

+

Description: The relative URL to the workflow step type's logo that will be displayed in the workflow editor.
The recommended resolution is 48x48 pixels.

@@ -99,8 +306,8 @@ You can grant access to this module to one of the following user categories: description

Type: string

-

Required: yes

-

Description: The human-readable description of what the module does.
+

Required: no

+

Description: The human-readable description of what the workflow step does.
The description will be visible in the Crowdin Enterprise UI.

@@ -109,7 +316,7 @@ You can grant access to this module to one of the following user categories:

Type: object

Required: yes

-

Description: Defines the input and output ports for the workflow step, determining how strings enter and exit the step.

+

Description: Defines the input and output ports for the workflow step, determining how strings enter and exit the step. Read more about Boundaries and Ports.

@@ -117,7 +324,7 @@ You can grant access to this module to one of the following user categories:

Type: object

Required: yes

-

Description: Specifies the properties of the input data for the workflow step, including available ports.

+

Description: Specifies the properties of the input data for the workflow step, including available ports. Exactly one input group is allowed.

@@ -125,7 +332,7 @@ You can grant access to this module to one of the following user categories:

Type: string

Required: yes

-

Description: The title for the input section of the workflow step.

+

Description: The title for the input section of the workflow step (3–30 characters).

@@ -142,7 +349,7 @@ You can grant access to this module to one of the following user categories:

Type: array

Required: yes

-

Description: Specifies the possible outputs of the workflow step, determining how processed strings move forward.

+

Description: Specifies the possible outputs of the workflow step, determining how processed strings move forward. A step can declare one or two outputs.

@@ -150,10 +357,11 @@ You can grant access to this module to one of the following user categories:

Type: object

Required: yes

+

Allowed values for port: untranslated, translated, approved, all, false, true, skipped

Description: Defines the outputs of the workflow step. Each object in the array contains:

@@ -163,7 +371,7 @@ You can grant access to this module to one of the following user categories:

Type: string

Required: no

Allowed values: side-by-side, comfortable, multilingual

-

Description: Defines the Crowdin Enterprise Editor mode for this workflow step.

+

Description: Defines the default Crowdin Enterprise Editor mode used when a user opens the Editor for this workflow step.

@@ -179,7 +387,7 @@ You can grant access to this module to one of the following user categories:

Type: string

Required: no

-

Description: The relative URL for deleting the workflow step in the workflow editor.

+

Description: The relative URL notified when the workflow step is deleted in the workflow editor.

@@ -187,7 +395,7 @@ You can grant access to this module to one of the following user categories:

Type: string

Required: no

-

Description: The relative URL to the iframe for configuring the workflow step settings.

+

Description: The relative URL to the iframe with the settings UI for the workflow step. The page is loaded in the workflow editor when a user configures the step.

@@ -202,16 +410,65 @@ You can grant access to this module to one of the following user categories: +### Boundaries and Ports + +The `boundaries` object declares the step's connectors in the workflow graph. Ports describe the state of the content that flows through them, not the steps they connect. An output of one step can be connected to an input of the next step if both use the same port, or if either side uses the `all` port. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PortMeaning
initialThe string arrived directly from the workflow's Start point without prior processing. Can be used only as an input.
untranslatedThe string has no translation yet.
translatedThe string has a translation.
approvedThe string's translation has been approved.
skippedThe string was bypassed by a previous step (e.g., pre-translation found no match).
true / falseA generic boolean pair for branching logic. These are the same connectors used by Custom Code steps.
allA wildcard that can be connected to any port on the other side.
+ +A common configuration is one "success" output (e.g., `translated`, `approved`, or `true`) and one "failure" or "bypass" output (e.g., `untranslated`, `skipped`, or `false`), letting the workflow route processed and unprocessed strings down different paths. + ## Communication Between App and Crowdin The Workflow Step Type module relies on webhooks and API methods to communicate with Crowdin Enterprise. Apps that include this module must also define the [Webhook module](/developer/crowdin-apps-module-webhook/) to receive string-related events (i.e., `string.status_on_step.recalculation_triggered`) and process them accordingly. ### Receiving Webhook Events from Crowdin -Crowdin Enterprise periodically sends a batched webhook payload to the app’s Webhook module whenever strings reach a custom workflow step provided by the app. +Crowdin Enterprise sends a batched webhook payload to the app's Webhook module whenever strings reach a custom workflow step provided by the app. When a string lands on the custom step (e.g., it was just added, moved there by a previous step, or re-triggered), its status on the step becomes **Need Process**, and the webhook event is queued for delivery. This payload contains the `string.status_on_step.recalculation_triggered` event and includes all relevant strings that need external processing (e.g., AI-based proofreading). + + Example webhook payload for the `string.status_on_step.recalculation_triggered` event: ```json @@ -331,15 +588,54 @@ Example webhook payload for the `string.status_on_step.recalculation_triggered` } ``` +### String Statuses on a Custom Step + +Each string on a custom workflow step has a status per target language. The statuses you will encounter when working with the [API methods](#api-methods): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaning
NEED_PROCESSThe string reached the step and is waiting for the app's decision. Counted as "to do" in the project's progress.
TODOThe app explicitly parked the string on the step by setting an empty output ("").
DONEThe app assigned the string to one of the step's output ports, and the string moved on in the workflow.
FAILEDWebhook delivery to the app failed. Strings in this status are shown as failed words in the project and are not resent automatically. Read more about Delivery Guarantees.
INCOMPLETEThe string was excluded from processing (e.g., hidden).
+ ### Processing Strings and Updating Their Status -1. **App Logic** - The app processes the received strings according to its internal logic (e.g., sending them to an AI service or performing custom validations). -2. [**Updating String Status via API**](#api-methods) - After processing, the app calls Crowdin Enterprise’s private API to update each string’s status on the custom workflow step. This action routes the strings to the appropriate workflow step outputs. +1. **Condition of Done** - The app evaluates its condition of done for the received strings according to its internal logic (e.g., sending them to an AI service or performing custom validations). +2. [**Updating String Status via API**](#api-methods) - After processing, the app calls the Crowdin Enterprise API to update each string's status on the custom workflow step. This action routes the strings to the appropriate workflow step outputs. #### API Methods Below are the API methods for managing string statuses on a custom workflow step. The **Update String Status** method is mandatory, as it finalizes string statuses and routes them to the correct workflow outputs. Another available method **Get Current String Status** is optional, but can help manage edge cases or advanced logic in your app. + +
Update String Status @@ -381,11 +677,16 @@ Below are the API methods for managing string statuses on a custom workflow step languageId Yes string - Target language code. + Target language code. Must be one of the step's target languages (see the workflowStep.languages property in the webhook payload). + The request body is a JSON Patch array. Only the `replace` operation is supported. The `path` has the format `/{stringId}/output`, and `value` must be either one of the output ports declared in the module's `boundaries.outputs` or an empty string: + + * A declared output port (e.g., `translated`) – the string is marked as **Done** on the step and immediately routed to the workflow step connected to that output. + * An empty string (`""`) – the string is parked on the step with the **To Do** status. Use this to keep strings pending (e.g., visible as remaining work) until your app finishes processing them. + **Request Body (example)**: ```json [ @@ -475,6 +776,45 @@ Below are the API methods for managing string statuses on a custom workflow step + **Query parameters:** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRequiredTypeDescription
stringIdsNostringFilter by string identifiers (comma-separated, up to 500 per request).
statusNostringFilter by status: TODO, DONE, INCOMPLETE, NEED_PROCESS, or FAILED.
limitNointegerMaximum number of items to retrieve.
offsetNointegerStarting offset in the collection.
+ **Response Example**: ```json { @@ -502,18 +842,36 @@ Below are the API methods for managing string statuses on a custom workflow step ```
+### Delivery Guarantees and Reconciliation + +Treat the webhook as a notification, not a reliable queue: + +* **Batching and delay** – events are delivered in batches and may arrive with a short delay after strings reach the step. +* **Limited retries** – if the app is unreachable or responds with an error, delivery is retried a limited number of times. After that, the affected strings are marked as **Failed** on the step and are not resent automatically. +* **Recovery from failures** – strings in the **Failed** status are shown as failed words in the project. A project manager can re-trigger their processing from the workflow step in Crowdin Enterprise, which resets them to **Need Process** and resends the webhook event. +* **No processing deadline** – strings can wait in the **Need Process** status indefinitely. Crowdin Enterprise does not expire or reassign them, so your app is responsible for eventually processing every string it receives. + +Because delivery is not guaranteed, we recommend that your app periodically reconciles its state with Crowdin Enterprise: call the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter for each active step and language to pick up strings whose webhook events your app may have missed, and process them as usual. + ### Configuring the Workflow Step in the Workflow Editor -Users can configure or delete a custom workflow step in the Crowdin Enterprise workflow editor: +Users can configure or delete a custom workflow step in the Crowdin Enterprise workflow editor. Crowdin Enterprise notifies your app about these changes via the `updateSettingsUrl` and `deleteSettingsUrl` callbacks. These notifications are your app's source of truth about which of its steps exist and how they are configured, so we recommend persisting the received data. * **Updating Settings (`updateSettingsUrl`)** - - When a user clicks **Save** after changing step settings in the workflow editor, Crowdin Enterprise sends a **POST** request to the `updateSettingsUrl` defined in the manifest. + - When a user clicks **Save** after adding or changing the step in the workflow editor, Crowdin Enterprise sends a **POST** request to the `updateSettingsUrl` defined in the app descriptor. + - For a step in a project workflow, the request body contains `organizationId`, `projectId`, `workflowId`, `stepId`, and `settings` (the step's condition of done configuration saved by the settings UI). + - For a step in a workflow template, the request body contains `organizationId`, `templateId`, `stepId`, and `settings`. - The app responds with a **2XX status** to confirm successful handling of the updated configuration. * **Deleting a Step (`deleteSettingsUrl`)** - When a user deletes the step in the workflow editor, Crowdin Enterprise sends a **DELETE** request to the `deleteSettingsUrl`. + - For a step in a project workflow, the request body contains `organizationId`, `projectId`, `workflowId`, and `stepId`. For a step in a workflow template, it contains `organizationId`, `templateId`, and `stepId`. - The app can safely remove any stored settings related to the deleted workflow step and respond with a **2XX status** to confirm success. + + ### Implementing the Settings UI in Your App If the workflow step provides any settings through the UI, you need to implement validation and saving of the workflow step configuration. @@ -541,3 +899,103 @@ To save the workflow step's configuration, use the following method: window.currentFormData = settings; AP.formDataUpdated(settings); ``` + +The saved settings are delivered back to your app via the `updateSettingsUrl` callback when the user saves the workflow. + +## Recommended Implementation Flow + + + 1. **Register an OAuth app** with the scopes your app needs (at least `project`). Read more about [Creating an OAuth application](/developer/authorizing-oauth-apps/). + 2. **Prepare the app descriptor**: set `authentication.type` to `crowdin_agent` with your `clientId`, declare the `agent` object, one or more `workflow-step-type` modules, and a `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event. Declare `updateSettingsUrl` and `deleteSettingsUrl` if your step has per-step configuration, and a `url` settings iframe so managers can edit it. + 3. **Handle the Installed event**: store the received credentials, including the `agentId`, and obtain an API token via the `crowdin_agent` grant type when needed. + 4. **Handle the settings callbacks**: persist the data received on `updateSettingsUrl` – it identifies each live step (`projectId`/`templateId`, `workflowId`, `stepId`) together with its settings. + 5. **Handle the webhook**: acknowledge quickly with a `2xx` response and queue the strings for processing. Remember that payloads arrive batched (`{"events": [...]}`), and verify the `X-Crowdin-Signature` header. + 6. **Process the strings** by evaluating your condition of done, and report the results with the **Update String Status** endpoint, assigning each string to an output port that reflects your decision, or `""` to keep it parked on the step. + 7. **Reconcile periodically**: query the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter to pick up strings whose webhook events your app may have missed. + 8. **Handle deletions**: drop the stored per-step state on `deleteSettingsUrl` requests, and treat app uninstallation as the deletion of all steps. + + +## Limitations + +* The module is available in Crowdin Enterprise only and works in projects that use workflows. +* The app must use the `crowdin_agent` authentication type and declare an `agent` object in the app descriptor. +* The app must include a Webhook module subscribed to the `string.status_on_step.recalculation_triggered` event. Otherwise, the step cannot receive strings for processing. +* The module is not available for serverless apps – an app backend (`baseUrl`) is required. +* A step declares exactly one input group and at most two outputs. Input and output titles are 3–30 characters long. The `initial` port can be used only as an input. +* The **Update String Status** endpoint supports only the `replace` operation, and the output value must be one of the step's declared output ports or an empty string. +* The **Get Current String Status** endpoint accepts up to 500 string identifiers per request. +* Webhook delivery is best-effort: events are batched, may arrive with a delay, and are retried a limited number of times. Implement periodic reconciliation to guarantee all strings get processed. +* The agent user must be invited as a manager to every project where the step is used. If the access is revoked, workflow validation fails and the app's API calls are rejected. + +## Troubleshooting + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SymptomCauseSolution
Installation fails with Only crowdin_agent authentication type is allowed for workflow-step-type module typeThe app descriptor uses crowdin_app or none authentication, or the authentication object is missingSet authentication.type to crowdin_agent, specify the clientId, and add the agent object
Installation fails with Serverless apps allow only UI module typesThe app descriptor has no baseUrlAdd a baseUrl – this module requires an app backend
Installation fails with Requested scopes exceed the access level specified in the OAuth appThe scopes in the app descriptor are broader than the scopes of the OAuth appAlign the app descriptor scopes with the OAuth app configuration
The step type doesn't appear in the workflow editorThe app is installed in Crowdin instead of Crowdin Enterprise; the current user has no access to the module; or the app has no Webhook module subscribed to the required eventInstall the app in Crowdin Enterprise, check the module access settings, and add the Webhook module for string.status_on_step.recalculation_triggered
Workflow validation error about manager permissions for the agentThe agent user doesn't have manager access to the projectInvite the agent user to the project as a manager
403 Forbidden on the string status endpointsThe access token was not obtained via the crowdin_agent grant type (e.g., it belongs to a regular user), or the agent is not a manager of the projectObtain the token via the crowdin_agent grant type with the agent_id parameter and verify the agent's project role
404 Not Found on the string status endpointsThe languageId is not among the step's target languages, or the step is not an active custom workflow stepUse the language codes from the webhook's workflowStep.languages property and verify the step identifier
400 Bad Request when updating the string statusThe output value is not one of the step's declared output portsSend one of the module's boundaries.outputs[].port values or an empty string
Strings are stuck as failed words on the stepWebhook delivery to the app failedFix the app availability, then re-trigger the failed strings from the workflow step in Crowdin Enterprise
The webhook never arrivesThe webhook module is subscribed to a wrong event, or it belongs to a different app than the stepSubscribe the Webhook module of the same app to the string.status_on_step.recalculation_triggered event
The webhook arrives with a delayEvents are queued and delivered in batches by designDesign your app for asynchronous processing
+ + + Read more about [App-based Workflow Steps](/enterprise/app-based-workflow-step/) from the organization management perspective. + diff --git a/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx b/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx index 8ab47dae4..6d38067b5 100644 --- a/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx +++ b/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx @@ -14,6 +14,8 @@ import workflowIssuesBanner from '!/enterprise/organization-management/workflow_ App-based workflow steps become available after you install specific apps from the [Crowdin Store](https://store.crowdin.com/) or add private apps to your Crowdin Enterprise organization. These steps can provide specialized functionality like AI-driven proofreading, delayed processing, etc., and are a powerful way to tailor workflows to your team's exact needs. By adding them to your workflow, you expand Crowdin Enterprise's default capabilities with unique conditions, automation, and integrations. +Unlike built-in steps, an app-based step comes with its own condition of done and routing logic defined by the app: the app decides when strings are considered complete on the step and which output they move through to the next workflow step. + ## Use Cases Below are a few examples of how app-based steps can enhance your workflows. Some are drawn from existing Crowdin Store apps, while others illustrate broader possibilities: @@ -49,6 +51,17 @@ Depending on the app, you may need specific permissions (e.g., Manager or Admin) Read more about [Installing Crowdin Apps](/developer/crowdin-apps-installation/#installation-in-crowdin-enterprise). +### Agent User + +When you install an app that provides workflow steps, Crowdin Enterprise creates a dedicated **agent** – a bot user that represents the app in your organization. The app processes strings on its workflow steps on behalf of this user, so all its actions are clearly attributed in the project activity. + +The agent must have manager access to every project where the app-based step is used: + +* During the app installation, you can assign the agent as a manager to all existing projects. +* Otherwise, invite the agent to the project as a manager when you add the app-based step to that project's workflow. + +If the agent's manager access is revoked, the workflow validation fails and the step stops processing strings, so avoid removing the agent from your project members. When the app is uninstalled, the agent user is removed automatically. + @@ -82,7 +95,8 @@ When an app-based step is misconfigured, Crowdin Enterprise flags the workflow a * **Error Banners and Inactive Steps** – If the app is removed or becomes inactive, your project's Dashboard may display a banner informing about the workflow issues with instructions on how to resolve them. Workflow Issues Banner In the workflow editor, you may see steps with failed validations (e.g., *The application required for this step type is uninstalled*). To fix this, reinstall the app and reconfigure its step, or remove the step if it's no longer needed. -* **Validation Warnings** – When saving changes to the workflow, a warning might appear if the app-based step is misconfigured or has unmet dependencies (e.g., *Workflow Delay Agent requires manager permissions*). +* **Validation Warnings** – When saving changes to the workflow, a warning might appear if the app-based step is misconfigured or has unmet dependencies (e.g., *Workflow Delay Agent requires manager permissions*). Warnings about manager permissions usually mean that the app's [agent user](#agent-user) lost manager access to the project – re-add the agent to the project members with the Manager role. +* **Failed Strings on the Step** – If the app couldn't be notified about strings that reached its step (e.g., the app's service was temporarily unavailable), those strings are counted as failed words on the step. Once the app is available again, a project manager can re-trigger processing of the failed strings from the workflow step, and they will be sent to the app again. * **No Access to the App-based Step** – Occasionally, an app-based step may not appear in the workflow editor if the app was installed with limited project access or if you lack the required role (e.g., Manager). Check your project settings to confirm you have Manager or Admin rights and that the app is allowed in the intended project. * **Connectivity or External Service Errors** – If an app-based step relies on a third-party service or API, timeouts or network failures may cause the step to fail or get stuck. * **Check Service Status**: Verify that any external service used by the app is online and functioning properly. From 3199a5da4151e4edca8152f1ac30a0bae7885cd3 Mon Sep 17 00:00:00 2001 From: Serhii Kozlovskyi Date: Thu, 6 Aug 2026 17:24:25 +0300 Subject: [PATCH 2/3] docs(developer): apply technical review feedback to the Workflow Step Type docs - correct what is validated at installation and how a missing Webhook module actually surfaces (silent non-delivery first, validation error only on later workflow saves) - document the JWT-signed settings callbacks, per-minute webhook batching, agent name/username handling, and the agentId Installed event property - clarify the INCOMPLETE status and quote real validation messages in Troubleshooting - restructure the module article: section order aligned with sibling articles, Limitations folded into existing sections, simple tables converted to Markdown - use "bot" terminology in the Enterprise article to match the UI - update the Installed event note in the App Installation article Co-Authored-By: Claude Fable 5 --- .../developer/crowdin-apps/app-descriptor.mdx | 9 +- .../developer/crowdin-apps/installation.mdx | 2 +- .../docs/developer/crowdin-apps/security.mdx | 2 +- .../modules/other/workflow-step-type.mdx | 525 +++++++----------- .../workflows/app-based-workflow-step.mdx | 18 +- 5 files changed, 226 insertions(+), 330 deletions(-) diff --git a/src/content/docs/developer/crowdin-apps/app-descriptor.mdx b/src/content/docs/developer/crowdin-apps/app-descriptor.mdx index 4dcebf746..6b6498c0a 100644 --- a/src/content/docs/developer/crowdin-apps/app-descriptor.mdx +++ b/src/content/docs/developer/crowdin-apps/app-descriptor.mdx @@ -176,7 +176,7 @@ Specifies the authentication type to use when signing requests from the host app In case your Crowdin app requires access to Crowdin API at any time, it’s recommended to use the `crowdin_app`, in other cases feel free to use the `none`. The authentication type `none` grants access to Crowdin API as well as the `crowdin_app`, but only when the Crowdin app is executed on the user side, for example, when the iframe opens. -The `crowdin_agent` type is used by apps that act as long-lived participants in projects (e.g., process strings on a custom workflow step). When such an app is installed, Crowdin creates a dedicated agent (bot) user, and the app's API calls are authenticated as that user. Read more about [agent authentication](/developer/crowdin-apps-module-workflow-step-type/#authentication). +The `crowdin_agent` type is for apps that keep working in your projects after installation, for example, apps that process strings on a custom workflow step. When such an app is installed, Crowdin creates a dedicated bot user, and the app's API calls are authenticated as that user. Read more about [agent authentication](/developer/crowdin-apps-module-workflow-step-type/#authentication). Example: @@ -367,6 +367,13 @@ Properties:

Description: The `baseUrl` of the organization in Crowdin Enterprise the app was installed to. For Crowdin the `baseUrl` value is always `https://crowdin.com`

+ + agentId + +

Type: integer

+

Description: The numeric identifier of the agent user created for the app. Sent only for apps with the crowdin_agent authentication type.

+ + diff --git a/src/content/docs/developer/crowdin-apps/installation.mdx b/src/content/docs/developer/crowdin-apps/installation.mdx index 7f61a2e12..3cd0d0b75 100644 --- a/src/content/docs/developer/crowdin-apps/installation.mdx +++ b/src/content/docs/developer/crowdin-apps/installation.mdx @@ -115,7 +115,7 @@ When a Crowdin App is installed in the Account Settings, an authorization flow t Communication between Crowdin and Crowdin App Let's examine each step in the illustration in detail: diff --git a/src/content/docs/developer/crowdin-apps/security.mdx b/src/content/docs/developer/crowdin-apps/security.mdx index 2a8fa617c..cf531572c 100644 --- a/src/content/docs/developer/crowdin-apps/security.mdx +++ b/src/content/docs/developer/crowdin-apps/security.mdx @@ -9,7 +9,7 @@ import { Aside } from '@astrojs/starlight/components'; To ensure the high level of security for cases when the Crowdin app works with the data from Crowdin (i.e. uses the authorization via `crowdin_app`), we've developed a security mechanism. The main principle of this security mechanism is based on the exchange of the JWT token between Crowdin and the Crowdin app. JWT token is signed with an OAuth Client Secret known only to the two final parties. This way, the Crowdin app can get a confirmation that the page is opened precisely in Crowdin. ## Implementation diff --git a/src/content/docs/developer/modules/other/workflow-step-type.mdx b/src/content/docs/developer/modules/other/workflow-step-type.mdx index 02ed279b0..f6ba06518 100644 --- a/src/content/docs/developer/modules/other/workflow-step-type.mdx +++ b/src/content/docs/developer/modules/other/workflow-step-type.mdx @@ -12,179 +12,21 @@ import ReadMore from '~/components/ReadMore.astro'; This module allows you to create custom workflow step types to extend the default list of workflow steps in Crowdin Enterprise. With this app installed, the new workflow step types become available in the workflow editor, where they can be added to workflows and templates, enabling greater customization and flexibility. -A custom workflow step acts as an external processing stage in a workflow: Crowdin Enterprise handles the routing of strings, status tracking, and progress counters, while your app implements the step's **condition of done** – the custom logic that decides when a string is considered complete on the step and which output it leaves through. Typical use cases include AI-based review, integration with an external review or MT system, compliance gates, or delay/scheduling steps. +A custom workflow step is an external processing stage in a workflow. Crowdin Enterprise routes the strings, tracks their status, and counts progress, while your app implements the step's condition of done: it decides when a string is complete on the step and which output it leaves through. Typical uses include AI-based review, integration with an external review or MT system, compliance gates, and delay or scheduling steps. ## How It Works -The Workflow Step Type module follows an asynchronous, event-driven integration model: +The module works asynchronously, driven by webhook events: 1. An organization admin installs the app. The custom step types provided by the app become available in the workflow editor. 2. A project manager adds the custom step to a workflow or workflow template and configures it via the settings UI provided by the app. 3. When strings reach the custom step, Crowdin Enterprise sends the `string.status_on_step.recalculation_triggered` webhook event to the app. - 4. The app evaluates its condition of done for the received strings. Processing is asynchronous and can take as long as needed. + 4. The app processes the received strings with its own logic. Processing is asynchronous and can take as long as needed. 5. The app updates the status of each processed string via the API, assigning it to one of the step's declared output ports according to its routing logic. 6. Crowdin Enterprise routes the strings to the next workflow step connected to that output. -## Requirements - -Apps that include the `workflow-step-type` module must meet all of the following requirements. An app descriptor that doesn't meet them will fail validation during installation: - -* **`crowdin_agent` authentication** – the app must use the `crowdin_agent` authentication type and declare an `agent` in the app descriptor. Other authentication types (e.g., `crowdin_app` or `none`) are not allowed for this module. Read more about [Authentication](#authentication). -* **Companion Webhook module** – the same app must also declare a [Webhook module](/developer/crowdin-apps-module-webhook/) subscribed to the `string.status_on_step.recalculation_triggered` event. Without it, the custom step cannot receive strings for processing. -* **App backend** – all module URLs are relative to the app's `baseUrl`, so the module is not compatible with [serverless apps](/developer/crowdin-apps-serverless/). -* **Crowdin Enterprise only** – custom workflow steps are available only in Crowdin Enterprise projects with workflows. - -## Authentication - -The `workflow-step-type` module requires the `crowdin_agent` authentication type. If the app descriptor uses any other authentication type (or omits the `authentication` object), the installation fails with the following error: - -> Only crowdin_agent authentication type is allowed for workflow-step-type module type - -### Why the Agent Authentication Type - -A custom workflow step is a long-lived participant in your projects rather than a UI extension. It processes strings asynchronously, triggered by webhooks, without any user session involved. To support this, Crowdin Enterprise creates a dedicated **agent** – a bot user that represents your app in the organization: - -* The agent user is created automatically when the app is installed and removed when the app is uninstalled. -* All API calls the app makes to process strings on the custom step are authenticated as the agent user. -* The agent must have manager access to every project where the custom step is used. A project manager invites the agent to the project as a manager as part of setting up the workflow step. Alternatively, the agent can be assigned as a manager to all existing projects during the app installation. -* All actions performed by the app are attributed to the agent user in the project activity, providing a clear audit trail. - -### Agent Declaration - -When using the `crowdin_agent` authentication type, the app descriptor must include a top-level `agent` object that describes the agent user: - -```json title="manifest.json" -{ - "authentication": { - "type": "crowdin_agent", - "clientId": "your-client-id" - }, - "agent": { - "name": "Custom Step", - "username": "custom-step-agent", - "avatarUrl": "/assets/agent-avatar.png" - } -} -``` - - - - - - - - - - - - - - - - -
agent.username -

Type: string

-

Required: yes

-

Description: The username for the agent user created in the organization.

-
agent.name -

Type: string

-

Required: no

-

Description: The display name of the agent user. If omitted, the app name is used.

-
agent.avatarUrl -

Type: string

-

Required: no

-

Description: The relative URL to the agent user's avatar. If omitted, the app logo is used.

-
- -### Obtaining an API Token - -The token flow for `crowdin_agent` is similar to the [`crowdin_app` flow](/developer/crowdin-apps-installation/#installed-event-communication-flow). When the app is installed, Crowdin sends the [Installed event](/developer/crowdin-apps-app-descriptor/#installed-event-payload) to the app. For apps with the `crowdin_agent` authentication type, the Installed event payload additionally contains the `agentId` property – the numeric identifier of the agent user created for your app. - -To obtain an API access token, the app sends the following request: - -```shell -POST https://accounts.crowdin.com/oauth/token -``` - -**Token request parameters:** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
grant_type: crowdin_agent -

Type: string

-

Required: yes

-

Description: Specifies the token flow for an agent app.

-
client_id -

Type: string

-

Required: yes

-

Description: The Client ID for the app is received when the app is registered.

-
client_secret -

Type: string

-

Required: yes

-

Description: The Client Secret for the app is received when the app is registered.

-
app_id -

Type: string

-

Required: yes

-

Description: Crowdin app identifier from the app descriptor.

-
app_secret -

Type: string

-

Required: yes

-

Description: The unique secret used to authorize your Crowdin app. This value is retrieved from the Installed event.

-
domain -

Type: string

-

Required: yes

-

Description: The name of the organization the app is installed to. This value is retrieved from the Installed event.

-
user_id -

Type: integer

-

Required: yes

-

Description: The identifier of the user who installed the app. This value is retrieved from the Installed event.

-
agent_id -

Type: integer

-

Required: yes

-

Description: The identifier of the agent user created for your app. This value is retrieved from the Installed event (agentId property).

-
- -The resulting access token is issued for the agent user. Use it in the `Authorization: Bearer` header for the [API methods](#api-methods) that manage string statuses on the custom step. - - - ## Access You can grant access to this module to one of the following user categories: @@ -195,7 +37,7 @@ You can grant access to this module to one of the following user categories: ## Structure -The example below shows a complete app descriptor for an app that provides a custom workflow step. Note the `crowdin_agent` authentication type, the `agent` object, and the companion `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event – all three are required: +The example below shows a complete app descriptor for an app that provides a custom workflow step. The `crowdin_agent` authentication type, the `agent` object, and the `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event are all required: ```json title="manifest.json" { @@ -412,48 +254,180 @@ The example below shows a complete app descriptor for an app that provides a cus ### Boundaries and Ports -The `boundaries` object declares the step's connectors in the workflow graph. Ports describe the state of the content that flows through them, not the steps they connect. An output of one step can be connected to an input of the next step if both use the same port, or if either side uses the `all` port. +The `boundaries` object declares the step's connectors in the workflow. A port describes the state of the content that flows through it, not the steps it connects. An output of one step can be connected to an input of the next step if both use the same port, or if either side uses the `all` port. + +| Port | Meaning | +|---|---| +| `initial` | The string arrived directly from the workflow's Start point without prior processing. Can be used only as an **input**. | +| `untranslated` | The string has no translation yet. | +| `translated` | The string has a translation. | +| `approved` | The string's translation has been approved. | +| `skipped` | The string was bypassed by a previous step (for example, pre-translation found no match). | +| `true` / `false` | A generic boolean pair for branching logic. These are the same connectors used by Custom Code steps. | +| `all` | A wildcard that can be connected to any port on the other side. | + +A common configuration is one "success" output (for example, `translated`, `approved`, or `true`) and one "failure" or "bypass" output (for example, `untranslated`, `skipped`, or `false`), so the workflow can route processed and unprocessed strings down different paths. + +## Requirements + +Apps that include the `workflow-step-type` module must meet all of the following requirements. Only the first two are validated when the app is installed: + +* **`crowdin_agent` authentication** – the app must use the `crowdin_agent` authentication type and declare an `agent` in the app descriptor. Other authentication types (for example, `crowdin_app` or `none`) are not allowed for this module. Read more about [Authentication](#authentication). +* **App backend** – all module URLs are relative to the app's `baseUrl`, so the module is not compatible with [serverless apps](/developer/crowdin-apps-serverless/). +* **Companion Webhook module** – the same app must also declare a [Webhook module](/developer/crowdin-apps-module-webhook/) subscribed to the `string.status_on_step.recalculation_triggered` event. Without it, there is no error at installation or when the step is added to a workflow – strings that reach the step are silently never delivered to the app. A validation error (*Some required dependencies are unmet*) appears only when the workflow is saved again later. +* **Crowdin Enterprise only** – custom workflow steps are available only in Crowdin Enterprise projects with workflows. In Crowdin (crowdin.com) the module is unavailable rather than rejected. + +## Authentication + +The `workflow-step-type` module requires the `crowdin_agent` authentication type. If the app descriptor uses any other authentication type (or omits the `authentication` object), the installation fails with the following error: + +> Only crowdin_agent authentication type is allowed for workflow-step-type module type + +### Why the Agent Authentication Type + +A custom workflow step keeps processing strings in your projects long after installation, triggered by webhooks and without a user session. For that, Crowdin Enterprise creates a dedicated **agent** (a bot user that represents your app in the organization): + +* The agent user is created automatically when the app is installed and removed when the app is uninstalled. +* All API calls the app makes to process strings on the custom step are authenticated as the agent user. +* The agent must have manager access to every project where the custom step is used. A project manager invites the agent to the project as a manager as part of setting up the workflow step. Alternatively, the agent can be assigned as a manager to all existing projects during the app installation. +* All actions the app performs are attributed to the agent user in the project activity. + +In the Crowdin Enterprise UI, the agent user is referred to as a *bot*. + +### Agent Declaration + +When using the `crowdin_agent` authentication type, the app descriptor must include a top-level `agent` object that describes the agent user: + +```json title="manifest.json" +{ + "authentication": { + "type": "crowdin_agent", + "clientId": "your-client-id" + }, + "agent": { + "name": "Custom Step", + "username": "custom-step-agent", + "avatarUrl": "/assets/agent-avatar.png" + } +} +``` - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - + +
PortMeaning
initialThe string arrived directly from the workflow's Start point without prior processing. Can be used only as an input.
untranslatedThe string has no translation yet.
translatedThe string has a translation.
approvedThe string's translation has been approved.
skippedThe string was bypassed by a previous step (e.g., pre-translation found no match).agent.username +

Type: string

+

Required: yes

+

Length: 3–128 characters

+

Description: The username for the agent user created in the organization. If the username is already taken, Crowdin appends a random suffix to it, so don't rely on the exact value you declared.

+
true / falseA generic boolean pair for branching logic. These are the same connectors used by Custom Code steps.agent.name +

Type: string

+

Required: no

+

Description: The display name of the agent user. Crowdin appends  Agent to this value. If omitted, the app name is used.

+
allA wildcard that can be connected to any port on the other side.agent.avatarUrl +

Type: string

+

Required: no

+

Description: The relative URL to the agent user's avatar. If omitted, the app logo is used.

+
-A common configuration is one "success" output (e.g., `translated`, `approved`, or `true`) and one "failure" or "bypass" output (e.g., `untranslated`, `skipped`, or `false`), letting the workflow route processed and unprocessed strings down different paths. +### Obtaining an API Token + +The token flow for `crowdin_agent` is similar to the [`crowdin_app` flow](/developer/crowdin-apps-installation/#installed-event-communication-flow). When the app is installed, Crowdin sends the [Installed event](/developer/crowdin-apps-app-descriptor/#installed-event-payload) to the app. For apps with the `crowdin_agent` authentication type, the Installed event payload also contains the `agentId` property, the numeric identifier of the agent user created for your app. + +To obtain an API access token, the app sends the following request: + +```shell +POST https://accounts.crowdin.com/oauth/token +``` + +**Token request parameters:** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
grant_type: crowdin_agent +

Type: string

+

Required: yes

+

Description: Specifies the token flow for an agent app.

+
client_id +

Type: string

+

Required: yes

+

Description: The Client ID for the app is received when the app is registered.

+
client_secret +

Type: string

+

Required: yes

+

Description: The Client Secret for the app is received when the app is registered.

+
app_id +

Type: string

+

Required: yes

+

Description: Crowdin app identifier from the app descriptor.

+
app_secret +

Type: string

+

Required: yes

+

Description: The unique secret used to authorize your Crowdin app. This value is retrieved from the Installed event.

+
domain +

Type: string|null

+

Required: yes

+

Description: The name of the organization the app is installed to. This value is retrieved from the Installed event.

+
user_id +

Type: integer

+

Required: yes

+

Description: The identifier of the user who installed the app. This value is retrieved from the Installed event.

+
agent_id +

Type: integer

+

Required: yes

+

Description: The identifier of the agent user created for your app. This value is retrieved from the Installed event (agentId property).

+
+ +The resulting access token is issued for the agent user. Use it in the `Authorization: Bearer` header for the [API methods](#api-methods) that manage string statuses on the custom step. + + ## Communication Between App and Crowdin @@ -461,12 +435,12 @@ The Workflow Step Type module relies on webhooks and API methods to communicate ### Receiving Webhook Events from Crowdin -Crowdin Enterprise sends a batched webhook payload to the app's Webhook module whenever strings reach a custom workflow step provided by the app. When a string lands on the custom step (e.g., it was just added, moved there by a previous step, or re-triggered), its status on the step becomes **Need Process**, and the webhook event is queued for delivery. +Crowdin Enterprise sends a batched webhook payload to the app's Webhook module whenever strings reach a custom workflow step provided by the app. When a string lands on the custom step (for example, it was just added, moved there by a previous step, or re-triggered), its status on the step becomes **Need Process** and the webhook event is queued for delivery. This payload contains the `string.status_on_step.recalculation_triggered` event and includes all relevant strings that need external processing (e.g., AI-based proofreading). Example webhook payload for the `string.status_on_step.recalculation_triggered` event: @@ -592,46 +566,27 @@ Example webhook payload for the `string.status_on_step.recalculation_triggered` Each string on a custom workflow step has a status per target language. The statuses you will encounter when working with the [API methods](#api-methods): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatusMeaning
NEED_PROCESSThe string reached the step and is waiting for the app's decision. Counted as "to do" in the project's progress.
TODOThe app explicitly parked the string on the step by setting an empty output ("").
DONEThe app assigned the string to one of the step's output ports, and the string moved on in the workflow.
FAILEDWebhook delivery to the app failed. Strings in this status are shown as failed words in the project and are not resent automatically. Read more about Delivery Guarantees.
INCOMPLETEThe string was excluded from processing (e.g., hidden).
+| Status | Meaning | +|---|---| +| `NEED_PROCESS` | The string reached the step and is waiting for the app's decision. Counted as "to do" in the project's progress. | +| `TODO` | The app explicitly parked the string on the step by setting an empty output (`""`). | +| `DONE` | The app assigned the string to one of the step's output ports, and the string moved on in the workflow. | +| `FAILED` | Webhook delivery to the app failed. Strings in this status are shown as failed words in the project and are not resent automatically. Read more about [Delivery Guarantees](#delivery-guarantees-and-reconciliation). | +| `INCOMPLETE` | The string is not currently routed to this step for that language (for example, it's hidden or excluded from the workflow). | ### Processing Strings and Updating Their Status -1. **Condition of Done** - The app evaluates its condition of done for the received strings according to its internal logic (e.g., sending them to an AI service or performing custom validations). +1. **App Logic** - The app processes the received strings according to its internal logic (for example, sending them to an AI service or running custom validations). 2. [**Updating String Status via API**](#api-methods) - After processing, the app calls the Crowdin Enterprise API to update each string's status on the custom workflow step. This action routes the strings to the appropriate workflow step outputs. #### API Methods Below are the API methods for managing string statuses on a custom workflow step. The **Update String Status** method is mandatory, as it finalizes string statuses and routes them to the correct workflow outputs. Another available method **Get Current String Status** is optional, but can help manage edge cases or advanced logic in your app. + + @@ -684,8 +639,8 @@ Below are the API methods for managing string statuses on a custom workflow step The request body is a JSON Patch array. Only the `replace` operation is supported. The `path` has the format `/{stringId}/output`, and `value` must be either one of the output ports declared in the module's `boundaries.outputs` or an empty string: - * A declared output port (e.g., `translated`) – the string is marked as **Done** on the step and immediately routed to the workflow step connected to that output. - * An empty string (`""`) – the string is parked on the step with the **To Do** status. Use this to keep strings pending (e.g., visible as remaining work) until your app finishes processing them. + * A declared output port (for example, `translated`) – the string is marked as **Done** on the step and immediately routed to the workflow step connected to that output. + * An empty string (`""`) – the string is parked on the step with the **To Do** status. Use this to keep strings pending (for example, visible as remaining work) until your app finishes processing them. **Request Body (example)**: ```json @@ -844,22 +799,22 @@ Below are the API methods for managing string statuses on a custom workflow step ### Delivery Guarantees and Reconciliation -Treat the webhook as a notification, not a reliable queue: +Don't rely on the webhook as a queue: -* **Batching and delay** – events are delivered in batches and may arrive with a short delay after strings reach the step. +* **Batching and delay** – events are collected into batches and sent once a minute, so they may arrive with a short delay after strings reach the step. * **Limited retries** – if the app is unreachable or responds with an error, delivery is retried a limited number of times. After that, the affected strings are marked as **Failed** on the step and are not resent automatically. * **Recovery from failures** – strings in the **Failed** status are shown as failed words in the project. A project manager can re-trigger their processing from the workflow step in Crowdin Enterprise, which resets them to **Need Process** and resends the webhook event. * **No processing deadline** – strings can wait in the **Need Process** status indefinitely. Crowdin Enterprise does not expire or reassign them, so your app is responsible for eventually processing every string it receives. -Because delivery is not guaranteed, we recommend that your app periodically reconciles its state with Crowdin Enterprise: call the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter for each active step and language to pick up strings whose webhook events your app may have missed, and process them as usual. +Because delivery is not guaranteed, reconcile your app's state with Crowdin Enterprise periodically: call the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter for each active step and language, and process the strings you get back as usual. ### Configuring the Workflow Step in the Workflow Editor -Users can configure or delete a custom workflow step in the Crowdin Enterprise workflow editor. Crowdin Enterprise notifies your app about these changes via the `updateSettingsUrl` and `deleteSettingsUrl` callbacks. These notifications are your app's source of truth about which of its steps exist and how they are configured, so we recommend persisting the received data. +Users can configure or delete a custom workflow step in the Crowdin Enterprise workflow editor. Crowdin Enterprise notifies your app about these changes via the `updateSettingsUrl` and `deleteSettingsUrl` callbacks, signed with the same `Authorization: Bearer` JWT as the iframe requests. These notifications are how your app learns which of its steps exist and how they are configured, so store the data you receive. * **Updating Settings (`updateSettingsUrl`)** - When a user clicks **Save** after adding or changing the step in the workflow editor, Crowdin Enterprise sends a **POST** request to the `updateSettingsUrl` defined in the app descriptor. - - For a step in a project workflow, the request body contains `organizationId`, `projectId`, `workflowId`, `stepId`, and `settings` (the step's condition of done configuration saved by the settings UI). + - For a step in a project workflow, the request body contains `organizationId`, `projectId`, `workflowId`, `stepId`, and `settings` (the step configuration saved by the settings UI). - For a step in a workflow template, the request body contains `organizationId`, `templateId`, `stepId`, and `settings`. - The app responds with a **2XX status** to confirm successful handling of the updated configuration. @@ -869,7 +824,7 @@ Users can configure or delete a custom workflow step in the Crowdin Enterprise w - The app can safely remove any stored settings related to the deleted workflow step and respond with a **2XX status** to confirm success. ### Implementing the Settings UI in Your App @@ -906,95 +861,29 @@ The saved settings are delivered back to your app via the `updateSettingsUrl` ca 1. **Register an OAuth app** with the scopes your app needs (at least `project`). Read more about [Creating an OAuth application](/developer/authorizing-oauth-apps/). - 2. **Prepare the app descriptor**: set `authentication.type` to `crowdin_agent` with your `clientId`, declare the `agent` object, one or more `workflow-step-type` modules, and a `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event. Declare `updateSettingsUrl` and `deleteSettingsUrl` if your step has per-step configuration, and a `url` settings iframe so managers can edit it. - 3. **Handle the Installed event**: store the received credentials, including the `agentId`, and obtain an API token via the `crowdin_agent` grant type when needed. - 4. **Handle the settings callbacks**: persist the data received on `updateSettingsUrl` – it identifies each live step (`projectId`/`templateId`, `workflowId`, `stepId`) together with its settings. - 5. **Handle the webhook**: acknowledge quickly with a `2xx` response and queue the strings for processing. Remember that payloads arrive batched (`{"events": [...]}`), and verify the `X-Crowdin-Signature` header. - 6. **Process the strings** by evaluating your condition of done, and report the results with the **Update String Status** endpoint, assigning each string to an output port that reflects your decision, or `""` to keep it parked on the step. - 7. **Reconcile periodically**: query the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter to pick up strings whose webhook events your app may have missed. - 8. **Handle deletions**: drop the stored per-step state on `deleteSettingsUrl` requests, and treat app uninstallation as the deletion of all steps. + 2. **Prepare the app descriptor** - set `authentication.type` to `crowdin_agent` with your `clientId`, declare the `agent` object, one or more `workflow-step-type` modules, and a `webhook` module subscribed to the `string.status_on_step.recalculation_triggered` event. Add `updateSettingsUrl`, `deleteSettingsUrl`, and the `url` settings iframe if your step has per-step configuration. + 3. **Handle the Installed event** - store the received credentials, including the `agentId`, and obtain an API token via the `crowdin_agent` grant type when needed. + 4. **Handle the settings callbacks** - persist the data received on `updateSettingsUrl`, which identifies each live step together with its settings. + 5. **Handle the webhook** - acknowledge quickly with a `2xx` response and queue the strings for processing. Payloads arrive batched (`{"events": [...]}`). Verify the `X-Crowdin-Signature` header. + 6. **Process the strings** with your own logic, and report the results with the **Update String Status** endpoint, assigning each string to an output port that reflects your decision, or `""` to keep it parked on the step. + 7. **Reconcile periodically** - query the **Get Current String Status** endpoint with the `status=NEED_PROCESS` filter to pick up strings whose webhook events your app may have missed. + 8. **Handle deletions** - drop the stored per-step state on `deleteSettingsUrl` requests, and treat app uninstallation as the deletion of all steps. -## Limitations - -* The module is available in Crowdin Enterprise only and works in projects that use workflows. -* The app must use the `crowdin_agent` authentication type and declare an `agent` object in the app descriptor. -* The app must include a Webhook module subscribed to the `string.status_on_step.recalculation_triggered` event. Otherwise, the step cannot receive strings for processing. -* The module is not available for serverless apps – an app backend (`baseUrl`) is required. -* A step declares exactly one input group and at most two outputs. Input and output titles are 3–30 characters long. The `initial` port can be used only as an input. -* The **Update String Status** endpoint supports only the `replace` operation, and the output value must be one of the step's declared output ports or an empty string. -* The **Get Current String Status** endpoint accepts up to 500 string identifiers per request. -* Webhook delivery is best-effort: events are batched, may arrive with a delay, and are retried a limited number of times. Implement periodic reconciliation to guarantee all strings get processed. -* The agent user must be invited as a manager to every project where the step is used. If the access is revoked, workflow validation fails and the app's API calls are rejected. - ## Troubleshooting - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SymptomCauseSolution
Installation fails with Only crowdin_agent authentication type is allowed for workflow-step-type module typeThe app descriptor uses crowdin_app or none authentication, or the authentication object is missingSet authentication.type to crowdin_agent, specify the clientId, and add the agent object
Installation fails with Serverless apps allow only UI module typesThe app descriptor has no baseUrlAdd a baseUrl – this module requires an app backend
Installation fails with Requested scopes exceed the access level specified in the OAuth appThe scopes in the app descriptor are broader than the scopes of the OAuth appAlign the app descriptor scopes with the OAuth app configuration
The step type doesn't appear in the workflow editorThe app is installed in Crowdin instead of Crowdin Enterprise; the current user has no access to the module; or the app has no Webhook module subscribed to the required eventInstall the app in Crowdin Enterprise, check the module access settings, and add the Webhook module for string.status_on_step.recalculation_triggered
Workflow validation error about manager permissions for the agentThe agent user doesn't have manager access to the projectInvite the agent user to the project as a manager
403 Forbidden on the string status endpointsThe access token was not obtained via the crowdin_agent grant type (e.g., it belongs to a regular user), or the agent is not a manager of the projectObtain the token via the crowdin_agent grant type with the agent_id parameter and verify the agent's project role
404 Not Found on the string status endpointsThe languageId is not among the step's target languages, or the step is not an active custom workflow stepUse the language codes from the webhook's workflowStep.languages property and verify the step identifier
400 Bad Request when updating the string statusThe output value is not one of the step's declared output portsSend one of the module's boundaries.outputs[].port values or an empty string
Strings are stuck as failed words on the stepWebhook delivery to the app failedFix the app availability, then re-trigger the failed strings from the workflow step in Crowdin Enterprise
The webhook never arrivesThe webhook module is subscribed to a wrong event, or it belongs to a different app than the stepSubscribe the Webhook module of the same app to the string.status_on_step.recalculation_triggered event
The webhook arrives with a delayEvents are queued and delivered in batches by designDesign your app for asynchronous processing
+| Error message | Likely cause | How to fix | +|---|---|---| +| Installation fails with *Only crowdin_agent authentication type is allowed for workflow-step-type module type* | The app descriptor uses `crowdin_app` or `none` authentication, or the `authentication` object is missing | Set `authentication.type` to `crowdin_agent`, specify the `clientId`, and add the `agent` object | +| Installation fails with *Serverless apps allow only UI module types* | The app descriptor has no `baseUrl` | Add a `baseUrl` – this module requires an app backend | +| Installation fails with *Requested scopes exceed the access level specified in the OAuth app* | The scopes in the app descriptor are broader than the scopes of the OAuth app | Align the app descriptor scopes with the OAuth app configuration | +| The step type doesn't appear in the workflow editor | The app is installed in Crowdin instead of Crowdin Enterprise; the current user has no access to the module; or the app has no Webhook module subscribed to the required event | Install the app in Crowdin Enterprise, check the module access settings, and add the Webhook module for `string.status_on_step.recalculation_triggered` | +| Workflow validation error *"\{agentName\}" requires manager permissions for the project* | The agent user doesn't have manager access to the project | Invite the agent user to the project as a manager | +| `403 Forbidden` on the string status endpoints | The access token was not obtained via the `crowdin_agent` grant type (for example, it belongs to a regular user), or the agent is not a manager of the project | Obtain the token via the `crowdin_agent` grant type with the `agent_id` parameter and verify the agent's project role | +| `404 Not Found` on the string status endpoints | The `languageId` is not among the step's target languages, or the step is not an active custom workflow step | Use the language codes from the webhook's `workflowStep.languages` property and verify the step identifier | +| `400 Bad Request` when updating the string status | The output value is not one of the step's declared output ports | Send one of the module's `boundaries.outputs[].port` values or an empty string | +| Strings are stuck as failed words on the step | Webhook delivery to the app failed | Fix the app availability, then re-trigger the failed strings from the workflow step in Crowdin Enterprise | +| The webhook never arrives, or re-saving the workflow fails with *Some required dependencies are unmet* | The app has no Webhook module subscribed to `string.status_on_step.recalculation_triggered`; the webhook module is subscribed to the wrong event; or it belongs to a different app than the step | Subscribe the Webhook module of the **same** app to the `string.status_on_step.recalculation_triggered` event | Read more about [App-based Workflow Steps](/enterprise/app-based-workflow-step/) from the organization management perspective. diff --git a/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx b/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx index 6d38067b5..3bea68185 100644 --- a/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx +++ b/src/content/docs/enterprise/organization-management/workflows/app-based-workflow-step.mdx @@ -14,7 +14,7 @@ import workflowIssuesBanner from '!/enterprise/organization-management/workflow_ App-based workflow steps become available after you install specific apps from the [Crowdin Store](https://store.crowdin.com/) or add private apps to your Crowdin Enterprise organization. These steps can provide specialized functionality like AI-driven proofreading, delayed processing, etc., and are a powerful way to tailor workflows to your team's exact needs. By adding them to your workflow, you expand Crowdin Enterprise's default capabilities with unique conditions, automation, and integrations. -Unlike built-in steps, an app-based step comes with its own condition of done and routing logic defined by the app: the app decides when strings are considered complete on the step and which output they move through to the next workflow step. +Unlike built-in steps, an app-based step defines its own completion rules: the app decides when strings are complete on the step and which output moves them to the next workflow step. ## Use Cases @@ -51,16 +51,16 @@ Depending on the app, you may need specific permissions (e.g., Manager or Admin) Read more about [Installing Crowdin Apps](/developer/crowdin-apps-installation/#installation-in-crowdin-enterprise). -### Agent User +### Bot User -When you install an app that provides workflow steps, Crowdin Enterprise creates a dedicated **agent** – a bot user that represents the app in your organization. The app processes strings on its workflow steps on behalf of this user, so all its actions are clearly attributed in the project activity. +When you install an app that provides workflow steps, Crowdin Enterprise creates a dedicated bot user that represents the app in your organization. The app processes strings on its workflow steps on behalf of this user, so its actions are attributed to the bot in the project activity. -The agent must have manager access to every project where the app-based step is used: +The bot must have manager access to every project where the app-based step is used: -* During the app installation, you can assign the agent as a manager to all existing projects. -* Otherwise, invite the agent to the project as a manager when you add the app-based step to that project's workflow. +* In the app installation dialog, select **Assign bot as a manager to all existing projects**. +* Otherwise, invite the bot to the project as a manager when you add the app-based step to that project's workflow. -If the agent's manager access is revoked, the workflow validation fails and the step stops processing strings, so avoid removing the agent from your project members. When the app is uninstalled, the agent user is removed automatically. +If the bot's manager access is revoked, the step fails validation and you can't publish the workflow, so the step stops processing strings. Keep the bot in the project members with the Manager role. When the app is uninstalled, the bot user is removed automatically.