# Changelog Source: https://www.activepieces.com/docs/about/changelog A log of all notable changes to Activepieces ### Stability & reliability improvements Major investments in worker architecture, testing, and resilience to ensure more reliable flow execution. **Worker Architecture** * Complete worker rewrite (worker v2) focused on stability and reliability * New sandbox process model with improved error handling and resource cleanup **Dedicated Workers** * Dedicated workers now run in isolated namespaces per platform * Custom pieces resolved per-platform for better isolation **Testing & Quality — what we added and why it matters** Race condition tests: * **Queue dispatcher** (12 tests) — tests orphaned job handling when a job is dequeued but all waiters have timed out, prevents double-loop spawn during close with in-flight dequeue, verifies single dequeue concurrency control, tests waiter timeout and retry behavior * **Subflow resume** (8 tests) — tests the race condition where the engine writes pause metadata to Redis before it's persisted to DB, verifies Redis fallback when DB is stale, simulates concurrent reads/writes with spy mocks, covers sync endpoint with concurrent Redis updates * **Rate limiter** (5+ tests) — tests concurrent job slot allocation, idempotency with concurrent dispatch, per-project isolation so different projects don't interfere * **Concurrent flow execution** — end-to-end test creating 5 concurrent flow runs verifying none get stuck or deadlocked * **Memory lock** — verifies mutual exclusion (two concurrent lock acquire calls on same key are serialized) Worker unit tests: * **Worker polling** — tests job execution lifecycle, resilience to invalid job data, null polls, unrecognized job types, mixed valid/invalid sequences * **Sandbox execution** — tests sandbox creation, startup, RPC communication, stdout/stderr accumulation, resource cleanup on timeout or memory issues, process cleanup and listener removal * **Process forking** — tests execArgv configuration (memory limits, node options), environment variable propagation * **Cache logic** — tests cache hit/miss, disk persistence, memory caching, cache invalidation predicates * **Configuration** — tests config loading for different container types (WORKER\_AND\_APP vs WORKER) End-to-end validation: * **[Smoke tests](https://github.com/activepieces/activepieces/blob/main/.github/workflows/smoke-test.yml) in GitHub Actions** — validates health checks and webhook flow execution on AMD64 and ARM64 * **[Benchmark tests](https://github.com/activepieces/activepieces/blob/main/.github/workflows/benchmark.yml) in GitHub Actions** — load testing across 6 app/worker configurations measuring throughput, mean latency, P50, P99 ([see results](/install/architecture/benchmark)) **Resilience** * Worker gracefully handles invalid job data, null polls, and unrecognized job types * Sandbox properly cleans up processes, listeners, and resources on timeout or memory issues * Race condition fixes for subflow resume and user interaction jobs ### Dashboard 2.0 — full UI redesign A comprehensive visual refresh across all Platform Admin and Project pages with a cleaner, more consistent interface. **Platform Admin** * **Projects** — filter chips, inline edit icons, and cleaner sidebar without branding * **Users** — new Role and Last Active columns, dedicated Invite button, and per-row action menus * **Project Roles** — switched from table to card-based layout with permission viewing * **Audit Logs** — fully enabled with Action, Performed By, Project, and Date Range filters, plus detail slide-over panels with a full JSON payload viewer * **Secret Managers** — card-based layout with Hashicorp Vault, AWS Secrets Manager, Cyberark Conjur, and 1Password * **Branding** — refreshed page layout **Project pages** * **Automations** — renamed from "Flows", with Type and Owner filters, search, step icon details, status toggles, and favorites * **Connections** — Pieces and Owner filters, flow usage count, inline edit and refresh actions * **Runs** — updated tab navigation and consistent styling **General improvements** * Unified tab navigation across Automations, Runs, and Connections * Platform Admin link added to the bottom of the project sidebar * Slide-over panels for detail views instead of full-page navigation * Previous / Next pagination style throughout * Sidebar header replaced with a "Back to app" link ### Dedicated staging environment & improved release process All changes now go through a dedicated staging environment before reaching production. Every update is validated internally for a minimum of 16 hours before being promoted, ensuring higher reliability and fewer disruptions for our users. * **Staging-first deployment** — every change is tested in a production-like environment before going live * **Daily production promotions** — only validated, stable builds are promoted to production * **Weekly self-hosted releases** — predictable, stable releases published every week for self-hosted customers * **Emergency hotfix path** — critical fixes can still be fast-tracked to production when needed [Read more about our release cycle](/handbook/engineering/onboarding/release-cycle) For previous releases, see the [GitHub Releases](https://github.com/activepieces/activepieces/releases) page. # i18n Translations Source: https://www.activepieces.com/docs/about/i18n This guide helps you understand how to change or add new translations. Activepieces uses Crowdin because it helps translators who don't know how to code. It also makes the approval process easier. Activepieces automatically sync new text from the code and translations back into the code. ## Contribute to existing translations 1. Create Crowdin account 2. Join the project [https://crowdin.com/project/activepieces](https://crowdin.com/project/activepieces) Join Project 3. Click on the language you want to translate 4. Click on "Translate All" Translate All 5. Select Strings you want to translate and click on "Save" button ## Adding a new language * Please contact us ([support@activepieces.com](mailto:support@activepieces.com)) if you want to add a new language. We will add it to the project and you can start translating. # License Source: https://www.activepieces.com/docs/about/license Activepieces' **core** is released as open source under the [MIT license](https://github.com/activepieces/activepieces/blob/main/LICENSE) and enterprise / cloud editions features are released under [Commercial License](https://github.com/activepieces/activepieces/blob/main/packages/ee/LICENSE) The MIT license is a permissive license that grants users the freedom to use, modify, or distribute the software without any significant restrictions. The only requirement is that you include the license notice along with the software when distributing it. Using the enterprise features (under the packages/ee and packages/server/api/src/app/ee folder) with a self-hosted instance requires an Activepieces license. If you are looking for these features, contact us at [sales@activepieces.com](mailto:sales@activepieces.com). **Benefits of Dual Licensing Repo** * **Transparency** - Everyone can see what we are doing and contribute to the project. * **Clarity** - Everyone can see what the difference is between the open source and commercial versions of our software. * **Audit** - Everyone can audit our code and see what we are doing. * **Faster Development** - We can develop faster and more efficiently. If you are still confused or have feedback, please open an issue on GitHub or send a message in the #contribution channel on Discord. # Event Streaming Source: https://www.activepieces.com/docs/admin-guide/guides/event-streaming Configure webhook destinations to receive real-time platform events ## Overview Event Streaming allows you to configure webhook destinations that receive real-time notifications when specific events occur in your Activepieces platform. This enables you to integrate Activepieces with external systems, monitoring tools, analytics platforms, or custom applications. ## Use Cases * **Monitoring & Analytics**: Track flow executions, user activity, and system changes in real-time * **Integration**: Sync events with external systems like SIEM tools, data warehouses, or custom dashboards * **Compliance**: Maintain audit trails in external systems for compliance requirements * **Automation**: Trigger downstream processes based on platform events ## Available Events You can configure destinations to receive the following event types: ### Flow Events * **Flow Created**: When a new flow is created * **Flow Updated**: When a flow is modified * **Flow Deleted**: When a flow is removed * **Flow Run Started**: When a flow execution begins * **Flow Run Finished**: When a flow execution completes * **Flow Run Resumed**: When a paused flow execution resumes ### Folder Events * **Folder Created**: When a new folder is created * **Folder Updated**: When a folder is modified * **Folder Deleted**: When a folder is removed ### Connection Events * **Connection Upserted**: When a connection is created or updated * **Connection Deleted**: When a connection is removed ### User Events * **User Signed Up**: When a new user registers * **User Signed In**: When a user logs in * **User Password Reset**: When a password reset is requested * **User Email Verified**: When a user verifies their email ### Security Events * **Signing Key Created**: When a new signing key is generated * **Project Role Created**: When a project role is created * **Project Role Updated**: When a project role is modified * **Project Role Deleted**: When a project role is removed * **Project Release Created**: When a project release is created ## How to Configure 1. Go to **Platform Admin → Infrastructure → Event Destinations** 2. Click **Create Destination** 3. Enter your **Webhook URL** (must be a valid HTTPS endpoint) 4. Select the **Events** you want to receive 5. Click **Test Destination** to verify the connection (optional) 6. Click **Create Destination** to save ## Requirements * **Enterprise Edition**: Event Streaming requires an enterprise plan with Audit Logs enabled * **HTTPS Endpoint**: Webhook URLs must use HTTPS * **Publicly Accessible**: Your endpoint must be accessible from the internet ## Troubleshooting * **Events Not Received**: Verify your endpoint is publicly accessible and returns 2xx status codes * **Test Fails**: Check that your URL is valid and uses HTTPS * **Missing Events**: Ensure the event type is selected in your destination configuration # Override OAuth2 Apps Source: https://www.activepieces.com/docs/admin-guide/guides/manage-oauth2 Use your own OAuth2 credentials instead of the default Activepieces apps ## Default Behavior When users connect to services like Google Sheets or Slack, they see "Activepieces" as the app requesting access. This works out of the box with no setup required. ## Why Replace OAuth2 Apps? * **Branding**: Show your company name instead of "Activepieces" in authorization screens * **Higher Limits**: Some services have stricter rate limits for shared OAuth apps * **Compliance**: Your organization may require using company-owned credentials ## How to Configure 1. Go to **Platform Admin → Setup → Pieces** 2. Find the piece you want to configure (e.g., Google Sheets) 3. Click the lock icon to open the OAuth2 settings 4. Enter your own Client ID and Client Secret Manage Oauth2 apps # How to Manage Pieces Source: https://www.activepieces.com/docs/admin-guide/guides/manage-pieces Control which integrations are available to your users ## Overview **Pieces** are the building blocks of Activepieces — they are integrations and connectors (like Google Sheets, Slack, OpenAI, etc.) that users can use in their automation flows. As a platform administrator, you have full control over which pieces are available to your users. This allows you to: * **Enforce security policies** by restricting access to certain integrations * **Simplify the user experience** by showing only relevant pieces for your use case * **Deploy custom/private pieces** that are specific to your organization There are **two levels** of piece management: | Level | Who Can Manage | Scope | | ------------------ | -------------- | --------------------------------------------- | | **Platform Level** | Platform Admin | Install and remove across the entire platform | | **Project Level** | Project Admin | Show/hide specific pieces for specfic project | *** ## Platform-Level Management Platform administrators can manage pieces for the entire Activepieces instance from **Platform Admin → Setup → Pieces**. ## Project-Level Management Project administrators can further restrict which pieces are available within their specific project. This is useful when different teams or projects need access to different integrations. ### Show/Hide Pieces in a Project Navigate to your project and go to **Settings → Pieces**. You'll see a list of all pieces installed on the platform. Toggle the visibility for each piece: * **Enabled**: Users in this project can use the piece * **Disabled**: The piece is hidden from users in this project Changes take effect immediately — users will only see the enabled pieces when building their flows. Manage Pieces Manage Pieces Project-level settings can only **hide** pieces that are installed at the platform level. You cannot add pieces at the project level that aren't already installed on the platform. ### Install Private Pieces For detailed instructions on building custom pieces, check the [Building Pieces](/build-pieces/building-pieces/overview) documentation. If you've built a custom piece for your organization, you can upload it directly as a tarball (`.tgz`) file. Build your piece using the Activepieces CLI: ```bash theme={null} npm run pieces -- build --name=your-piece-name ``` This generates a tarball in `dist/packages/pieces/your-piece-name`. Go to **Platform Admin → Setup → Pieces** and click **Install Piece**. Choose **Upload File** as the installation source. Select the `.tgz` file from your build output and upload it. Install Piece # Manage User Roles Source: https://www.activepieces.com/docs/admin-guide/guides/permissions Documentation on project permissions in Activepieces Activepieces utilizes Role-Based Access Control (RBAC) for managing permissions within projects. Each project consists of multiple flows and users, with each user assigned specific roles that define their actions within the project. ## Default Roles Activepieces comes with four standard roles out of the box. The table below shows the permissions for each role: | Permission | Admin | Editor | Operator | Viewer | | -------------------------- | :---: | :----: | :------: | :----: | | **Flows** | | | | | | View Flows | ✓ | ✓ | ✓ | ✓ | | Edit Flows | ✓ | ✓ | | | | Publish / Toggle Flows | ✓ | ✓ | ✓ | | | **Runs** | | | | | | View Runs | ✓ | ✓ | ✓ | ✓ | | Retry Runs | ✓ | ✓ | ✓ | | | **Connections** | | | | | | View Connections | ✓ | ✓ | ✓ | ✓ | | Edit Connections | ✓ | ✓ | ✓ | | | **Team** | | | | | | View Project Members | ✓ | ✓ | ✓ | ✓ | | Add/Remove Project Members | ✓ | | | | | **Git Sync** | | | | | | Configure Git Repo | ✓ | | | | | Pull Flows from Git | ✓ | | | | | Push Flows to Git | ✓ | | | | ## Custom Roles If the default roles don't fit your needs, you can create custom roles with specific permissions. Go to **Platform Admin** → **Security** → **Project Roles** Click **Create Role** and give it a name Select the specific permissions you want to grant to this role Custom roles are useful when you need fine-grained control, such as allowing users to view and retry runs without being able to edit flows. # Project Releases Source: https://www.activepieces.com/docs/admin-guide/guides/project-releases Learn how to manage and deploy releases across projects Project Releases allow you to sync flows, connections, and tables between different projects—essential for teams that want to develop in one environment and deploy to another with confidence. **Example:** Build and test your automations in a **Staging** project, then seamlessly promote them to **Production** when ready. Simply navigate to your Production project → **Releases** → create a release from Staging, and all your changes will be applied instantly. ## Overview There are three ways to create a release: | Source | Description | | ------------ | ------------------------------------------------ | | **Git** | Pull changes from a connected Git repository | | **Project** | Copy flows from another project in your instance | | **Rollback** | Restore a previous release state | ## Prerequisites ### Enabling Environments In your project dashboard, go to settings then to Environments and hit the enable button. Enable Environments Enable Environments ## Getting Started Navigate to the **Releases** page from your project sidebar to view all releases and create new ones. Project Releases Page ## Connecting Git (Optional) If you want to use Git to track your changes, you'll need to connect a Git repository first. This requires the Environments feature to be enabled. ## Creating a Release ### From Project Apply changes from flows, connections and tables in one project to another. Click the **Create Release** dropdown button. Choose **From Project** from the dropdown menu. Choose the project you want to copy flows, connections and tables from. Review the changes, and click **Apply Changes**. Create Release from Project Create Release from Project New connections created during a release are placeholders and need to be reconnected with valid credentials after the release is applied. ### From Git Click the **Create Release** dropdown button. Choose **From Git** from the dropdown menu. A dialog will appear showing all the changes that will be applied: * **Flows Changes**: New, updated, or deleted flows * **Connections Changes**: New or renamed connections * **Tables Changes**: New, updated, or deleted tables Check or uncheck the flows you want to include in this release. Enter a **Name** and optional **Description** for your release. Click **Apply Changes** to create the release. Create Release from Git ## Push Everything to Git If your project is connected to a Git repository, you can push all your flows, connections, and tables to Git. Click the **Push Everything** button on the releases page. Write a descriptive commit message explaining your changes. Click **Push** to send all published flows to the Git repository. Push Everything to Git Dialog ## Pushing Individual Flows or Tables You can also push specific flows or tables to Git without pushing everything. You can only push published flows to git Navigate to your flows or tables and select the items you want to push. Click the **Push to Git** option. Provide a commit message describing what you're pushing. Click **Push** to send the selected items to Git. Push to Git Dialog Push to Git Dialog ## Rolling Back a Release If something goes wrong after applying a release, you can easily rollback to a previous state. Locate the release you want to rollback to in the releases list. Click the rollback icon (↩) next to the release. Review the changes that will be applied to restore that release state. Select the changes to include and click **Apply Changes**. Rollback Release ## Release Details Each release in the list shows: | Column | Description | | --------------- | ------------------------------------------------------- | | **Name** | The name you gave the release | | **Source** | Where the release came from (Git, Project, or Rollback) | | **Imported At** | When the release was created | | **Imported By** | The user who created the release | Click on any release to view its full details. Release Details ## Understanding the Changes Preview When creating a release, you'll see a preview of all changes: ### Flow Changes * New flows that will be created * Existing flows that will be updated * Flows that will be deleted ### Connection Changes * New connections are placeholders and must be reconnected after the release * Renamed connections ### Table Changes * New, updated, and deleted tables are shown with their respective indicators ## Best Practices Give your releases meaningful names like "v1.2.0 - Added email notifications" to easily identify them later. Always review the changes preview carefully before applying a release to avoid unexpected modifications. If using Git sync, test changes in a development project before deploying to production. Use the description field to document what changed and why for future reference. ## Permissions To create and manage releases, you need the **Write Project Release** permission. Contact your instance administrator if you don't have access to the releases feature. ## Troubleshooting The Environments feature must be enabled on your instance plan to use Git sync. Contact your instance administrator to upgrade your plan or enable this feature. * Verify your SSH private key is correctly formatted (ends with an endline), and make sure it has an empty phrase. * Ensure the remote URL is in SSH format (not HTTPS) * Check that the branch exists in the repository If no changes appear when creating a release, it means your current project is already in sync with the source. After applying a release with new connections, navigate to the Connections page and reconnect them with valid credentials. Make sure you configured your git settings and if you are selecting flows, make sure they are published. Navigate to **Project Settings** from the sidebar, then click on **Environment**. If you don't see this option, the Environments feature may not be enabled for your instance. # SCIM Overview Source: https://www.activepieces.com/docs/admin-guide/guides/scim/overview Automate user lifecycle management with SCIM in Activepieces. ## What is SCIM? SCIM (System for Cross-domain Identity Management) lets your identity provider automatically create, update, and deactivate users in Activepieces. ## What SCIM Handles * **Provision users** when they are assigned in your identity provider * **Sync profile updates** such as name or email changes * **Deprovision users** when access is removed or accounts are deactivated ## SCIM and SSO SCIM handles user lifecycle management.\ SSO handles sign-in and authentication. You can use both together so user access is managed centrally in your identity provider. ## Supported Providers Configure SCIM provisioning from Okta to Activepieces. ## Configuration | Variable | Description | Default | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------ | -------- | | `AP_SCIM_DEFAULT_PROJECT_ROLE` | The project role assigned to members when added via SCIM group sync. Accepted values: `Admin`, `Editor`, `Viewer`. | `Editor` | ## Architecture SCIM Architecture Placeholder Replace this placeholder with your final architecture image later. Keep the same image path to avoid doc changes. # SCIM with Okta Source: https://www.activepieces.com/docs/admin-guide/guides/scim/providers/okta Configure SCIM provisioning from Okta to Activepieces. ## Prerequisites Before you start, make sure you have: * **Admin access** to your Activepieces platform * **Admin access** to your Okta tenant * SSO already configured (recommended): [SAML with Okta](/admin-guide/guides/sso#saml-with-okta) * Generated an API key from `/platform/security/api-keys` route in the Activepieces app ## Configure SCIM Connection in Okta In Okta Admin Console, open your Activepieces application (created in [SSO step](/admin-guide/guides/sso#saml-with-okta)). In the app's **General** tab, enable **SCIM Provisioning**. Okta User Provisioning Placeholder **Provisioning** will be visible, go to it and set: * **SCIM base URL** to `https://your-activepieces-domain/api/v1/scim/v2` * **Unique identifier field** to `userName` * **Authentication mode** to `HTTP Header` * **Authorization** to `Bearer ` In Supported provisioning actions we support all **Push** actions Click **Test Connector Configuration** and confirm the test passes. Okta SCIM Connection Image ## Configure Attribute Mapping In **Provisioning -> To App -> Attribute Mappings**, map these fields: | Activepieces (SCIM) | Okta Value | | ------------------- | ------------------ | | `userName` | `user.email` | | `givenName` | `user.firstName` | | `familyName` | `user.lastName` | | `email` | `user.email` | | `displayName` | `user.displayName` | ## Platform role mapping By default, provisioned users will have `Member` role in the platform. In order to specify roles for users in Okta, follow these steps: In Okta admin console, navigate to **Directory -> Profile Editor -> Your-Application User**. Click **Add Attribute** and fill form with: | Field | Value | | -------------------- | -------------------------------------------------------------------- | | `Display name` | `platformRole` | | `Variable name` | `platformRole` | | `External name` | `platformRole` | | `External namespace` | `urn:ietf:params:scim:schemas:activepieces:1.0:CustomUserAttributes` | | `Enum` | `enabled` | For **Attribute members**, add: | Display name | Value | | ------------ | ---------- | | `ADMIN` | `ADMIN` | | `MEMBER` | `MEMBER` | | `OPERATOR` | `OPERATOR` | Okta add attribute image Finally click save. This step assumes that you already have a field in the Okta user profile that you can map to platformRole in your Activepieces user profile. If you don't have one, you can create a new field in **Directory -> Profile Editor -> User (default)**. * Back to your Activepieces application page in **Provisioning -> To App -> Attribute Mappings** * Scroll down and click **Show Unmapped Attributes** * Edit `platformRole` field * Here you need to map the attribute value from your Okta user profile. If you already have a role field in the Okta user profile that matches exactly with a platformRole value (`ADMIN`, `MEMBER`, `OPERATOR`) then you can select it directly with `Map from Okta Profile` option, otherwise you can use an [Expression](https://developer.okta.com/docs/reference/okta-expression-language/) to return one of the 3 roles based on other fields in the Okta user profile. Here is an example of an expression: Okta role expression example Please make sure the return value to always be one of `ADMIN`, `MEMBER` or `OPERATOR` ## Provision and Deprovision Users ### Provision In the Activepieces application page, go to **Provisioning -> To App** and enable the actions you want to be applied to Activepieces when changes occur in Okta. Okta role expression example Now in the **Assignments** tab you can: * Choose to provision individual users or groups. Note that groups in Okta will be projects in Activepieces. * In case you don't have groups and you want to provision your Okta users at once, you can assign the `Everyone` group. * When editing/creating users in an assigned group (including `Everyone`), they should be updated in Activepieces. * To push groups to Activepieces, go to the **Push groups** tab and click on the push button, find the group and save. Default role for users in projects will be `Editor` role, right now there is no way to link the project role with Okta Okta role expression example Created users in Activepieces will receive a welcome email. When clicked, they will be redirected to sign in with `SAML`. ### Deprovision Users' state switches to `INACTIVE` in Activepieces only when they are deactivated in Okta. Suspension or deletion in Okta does not reflect in Activepieces because of Okta's design. For groups you can delete them in **Push groups** tab -> click on button in **Push Status** column -> Unlink pushed group -> Delete the group in target Deleting a group will delete the whole project in Activepieces with its flows and connections. Users linked to that group won't be affected. ## Troubleshooting * Confirm SCIM base URL is correct. * Ensure the `Authorization` header uses `Bearer` format. * Ensure users are assigned to the Okta app. * Confirm provisioning actions are enabled in Okta. * Recheck mappings in **Provisioning -> To App**. * Ensure `userName` uses a stable unique value (usually email). # AWS Secrets Manager Source: https://www.activepieces.com/docs/admin-guide/guides/secret-managers/aws Connect AWS Secrets Manager to Activepieces for centralized secret management AWS Secrets Manager helps you protect access to your applications, services, and IT resources. This integration uses **IAM user credentials** (Access Key + Secret Key) to authenticate directly with AWS Secrets Manager. ## Prerequisites * An AWS account with permissions to create IAM users and policies * Permissions to create and manage secrets in AWS Secrets Manager ## Step 1 — Create an IAM policy for Secrets Manager access Create an IAM policy that grants read access to the secrets Activepieces will retrieve. 1. Open the [IAM console → Policies → Create policy](https://console.aws.amazon.com/iam/home#/policies\$new?step=edit). 2. Switch to the **JSON** tab and paste: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue", "secretsmanager:ListSecrets", "secretsmanager:DescribeSecret" ], "Resource": "*" } ] } ``` For production, scope `Resource` to the specific secret ARNs Activepieces needs instead of using `"*"`. 3. Click **Next**, name the policy (e.g. `ActivepiecesSecretsReadOnly`), and create it. ## Step 2 — Create an IAM user and attach the policy 1. Open the [IAM console → Users → Create user](https://console.aws.amazon.com/iam/home#/users\$new). 2. Enter a username (e.g. `activepieces-secrets-user`) and click **Next**. 3. Select **Attach policies directly**, find and attach the policy created in Step 1, then click **Next** and **Create user**. 4. Open the newly created user, go to the **Security credentials** tab, and click **Create access key**. 5. Select **Application running outside AWS**, click **Next**, then **Create access key**. 6. Copy the **Access Key** and **Secret Key** — you will need both in the next step. ## Step 3 — Connect in Activepieces 1. Go to **Platform Admin → Security → Secret Managers**. 2. Select **AWS Secrets Manager** from the provider list. 3. Enter the connection details: * **Access Key** — the Access Key ID from Step 2 (e.g. `AKIAIOSFODNN7EXAMPLE`). * **Secret Key** — the Secret Access Key from Step 2. * **Region** — the AWS region where your secrets are stored (e.g. `us-east-1`). 4. Click **Connect** to test and save the connection. ## Using AWS Secrets Manager in connections When configuring a global connection that requires credentials: 1. Click the **key icon** (🔑) next to the credential field. 2. Select **AWS Secrets Manager** as the secret manager. 3. Fill in: * **Secret Name** — the friendly name of the secret in AWS Secrets Manager. * **Secret Json key** — Key of row for the stored secret. Activepieces will use the configured credentials to retrieve the secret value and inject it into the connection at runtime. If you update existing secrets and you can't see the update reflected . refer to [caching](/admin-guide/guides/secret-managers/overview#caching) # CyberArk Conjur Source: https://www.activepieces.com/docs/admin-guide/guides/secret-managers/cyberark-conjur Connect CyberArk Conjur to Activepieces for centralized secret management CyberArk Conjur is a secrets management solution that provides secure storage and access to credentials. Integration with Activepieces uses **host/API key authentication**: Activepieces authenticates as a Conjur host, receives a short-lived token, and uses it to retrieve secrets for which that host has `read` and `execute` permissions. Conjur policies are defined in `.yml` files. For recommended structure and patterns, see [Policy best practices](https://docs.cyberark.com/conjur-enterprise/13.0/en/Content/Operations/Policy/policy-best-practices.htm) in the CyberArk Conjur documentation. For policy syntax and operators, see the [Policy syntax](https://docs.cyberark.com/conjur-open-source/Latest/en/Content/Operations/Policy/policy-syntax.htm) reference. ## Prerequisites * A Conjur server (Conjur Cloud, Conjur Enterprise, or Conjur Open Source) * A Conjur policy that defines a host for Activepieces and grants it access to the variables you want to use ## Conjur host configuration for Activepieces To allow Activepieces to read secrets, configure a Conjur policy that declares a group, variables, a host, a layer, and the right permissions. The steps below describe how to create that policy file. ### Example policy (Activepieces) The following policy defines a policy `activepieces` with a group, two variables, a host, a layer, and the grants so the host can read the variables. ```yaml theme={null} - !policy id: activepieces body: - !group activepieces-secrets - &variables - !variable id: key-1 kind: password - !variable id: key-2 kind: password - !permit role: !group /activepieces/activepieces-secrets privileges: [read, update, execute] resources: *variables - !host activepieces - !layer activepieces - !grant role: !layer activepieces members: - !host activepieces - !grant role: !group activepieces-secrets member: !layer activepieces ``` ### Policy steps (summary) 1. **Declare a group** at the root of the policy (e.g. `activepieces-secrets`). This group will be allowed to read (and optionally execute) the variables. 2. **Declare variables** and give the group `read` and `execute` on them (so the host can fetch secret values): ```yaml theme={null} - &variables - !variable id: my-secret kind: password - !permit role: !group /your-policy/your-group privileges: [read, execute] resources: *variables ``` 3. **Declare the host** that Activepieces will use (e.g. `activepieces`) and a **layer** (e.g. `activepieces`), and add the host to the layer: ```yaml theme={null} - !host activepieces - !layer activepieces - !grant role: !layer activepieces members: - !host activepieces ``` 4. **Grant the layer membership in the group** that has access to the variables: ```yaml theme={null} - !grant role: !group activepieces-secrets member: !layer activepieces ``` 5. **Load the policy** into Conjur. Conjur will create the host and return an **API key** for that host. You will use this API key and the host identity when connecting Activepieces. After loading the policy, Conjur returns something like: ```json theme={null} { "created_roles": { "conjur:host:activepieces/activepieces": { "id": "conjur:host:activepieces/activepieces", "api_key": "" } }, "version": 1 } ``` Store the **api\_key** securely; you will enter it in Activepieces as the **API Key**. ## Server URL and organization * **Conjur Cloud**: Use a URL of the form\ `https://.secretsmgr.cyberark.cloud/api/`\ and set **Organization account name** to `conjur` unless your Cloud tenant uses a different account. * **On-prem / Enterprise**: Use your Conjur server base URL (e.g. `https://conjur.example.com`) and your organization account name. ## Connecting to Activepieces 1. Go to **Platform Admin → Security → Secret Managers**. 2. Select **CyberArk Conjur** from the provider list. 3. Enter the connection details: * **URL**: Conjur server URL (e.g. `https://conjur.example.com` or Conjur Cloud URL above). Do not add a trailing slash. * **Organization account name**: Your Conjur account (e.g. `conjur` for Conjur Cloud). * **Login ID**: For host authentication this must be the Conjur host ID with a `host/` prefix, e.g. `host/activepieces/activepieces` (policy id and host name as in your policy). * **API Key**: The host API key returned when the host was created (see policy load response above). 4. Click **Connect** to test and save the connection. ## Using CyberArk Conjur secrets in connections When configuring a connection that uses a secret: 1. Click the **key icon** (🔑) next to the credential field. 2. Select **CyberArk Conjur** as the secret manager. 3. Enter the **Secret key**: the Conjur variable path in the form `policy_id/variable_id`.\ For the example policy above, use: * `activepieces/key-1` * `activepieces/key-2` Activepieces will authenticate as the configured host and retrieve the secret from Conjur when the flow runs. If you update existing secrets and you can't see the update reflected . refer to [caching](/admin-guide/guides/secret-managers/overview#caching) # HashiCorp Vault Source: https://www.activepieces.com/docs/admin-guide/guides/secret-managers/hashicorp Connect HashiCorp Vault to Activepieces for enterprise-grade secret management HashiCorp Vault is an enterprise-grade secrets management system that provides secure storage and access to secrets, API keys, passwords, and other sensitive data. ## Prerequisites Before connecting HashiCorp Vault to Activepieces, ensure you have: * **HashiCorp Vault Key-value (KV) secrets engine** version 2 * **AppRole auth method** [enabled](https://developer.hashicorp.com/vault/docs/auth/approle) * **One or more AppRoles** [configured](https://developer.hashicorp.com/vault/docs/auth/approle) with appropriate policies ## Policies Enable The created AppRole to access your secrets engine(s) by adding the following to your policy ``` path "sys/mounts" { capabilities = [ "read" ] } path "/data/" { capabilities = [ "read" ] } ``` or ``` path "sys/mounts" { capabilities = [ "read" ] } path "/data/*" { capabilities = [ "read" ] } ``` ## Connecting to Activepieces 1. Go to **Platform Admin → Security → Secret Managers** 2. Select **HashiCorp Vault** from the provider list 3. Enter the required connection details: * **URL**: Your Vault server URL (e.g., `http://localhost:8200`) * **Role ID**: The Role ID from your AppRole configuration * **Secret ID**: The Secret ID from your AppRole configuration * **Namespace** (optional): Vault namespace if using Vault Enterprise namespaces 4. Click **Connect** to test and save the connection ## Using HashiCorp Vault Secrets When configuring a connection that requires credentials: 1. Go to **Platform Admin -> Setup -> Global connections** and create a conneciton 2. Click the **key icon** (🔑) next to the input field 3. Select **HashiCorp Vault** from the dropdown 4. Enter the secret path in the format: `mount/data/path/key` * if key is added via cli command `vault kv put -mount=secret sec api_key='mysec'` * the input value should be secret/data/mysec/api\_key Manage Oauth2 apps The connection will automatically retrieve the secret from Vault when the flow runs. If you update existing secrets and you can't see the update reflected . refer to [caching](/admin-guide/guides/secret-managers/overview#caching) # 1Password Source: https://www.activepieces.com/docs/admin-guide/guides/secret-managers/onepassword Connect 1Password to Activepieces for centralized secret management 1Password Secrets Automation lets you securely store and retrieve credentials from 1Password vaults. This integration uses a **service account token** to authenticate with the 1Password SDK. ## Prerequisites * A 1Password account with the **Teams** or **Business** plan (service accounts require a paid plan) * Permission to create service accounts in your 1Password account ## Step 1 — Create a service account 1. Sign in to [1password.com](https://1password.com) and go to **Developer Tools → Service Accounts**. 2. Click **Create a service account**. 3. Give it a name (e.g. `Activepieces`). 4. Grant it **Read Items** access on the vaults Activepieces needs to access. 5. Click **Create service account** and copy the token — it starts with `ops_` and is shown only once. Store the token securely. Once you leave the page, 1Password will not show it again. ## Step 2 — Connect in Activepieces 1. Go to **Platform Admin → Security → Secret Managers**. 2. Select **1Password** from the provider list. 3. Paste the **Service Account Token** from Step 1. 4. Click **Connect** to test and save the connection. ## Using 1Password in connections When configuring a global connection that requires credentials: 1. Click the **key icon** (🔑) next to the credential field. 2. Select **1Password** as the secret manager. 3. Enter the **Secret Reference** in the format: ``` op://vault/item/field ``` * **vault** — the vault name or ID (e.g. `Production`) * **item** — the item title or ID (e.g. `Stripe`) * **field** — the field label within the item (e.g. `password`, `api key`) Activepieces will retrieve the secret value from 1Password and inject it into the connection at runtime. The easiest way to get the exact reference is to open the 1Password desktop app, right-click any field, and select **Copy Secret Reference**. This copies the `op://...` string ready to paste. ## Example secret references | 1Password location | Reference | | ------------------------------------------------------- | ----------------------------------- | | Vault `Production` → Item `Stripe` → Field `Secret Key` | `op://Production/Stripe/Secret Key` | | Vault `Shared` → Item `Database` → Field `password` | `op://Shared/Database/password` | If you update existing secrets and you can't see the update reflected, refer to [caching](/admin-guide/guides/secret-managers/overview#caching). # Overview Source: https://www.activepieces.com/docs/admin-guide/guides/secret-managers/overview Connect external secret management systems to securely store and retrieve credentials Secret Managers allow you to integrate external secret management systems with Activepieces, enabling centralized credential management and enhanced security for your global connections. ## Benefits * **Centralized Management**: Store all credentials in one secure location * **Enhanced Security**: Credentials are managed by dedicated secret management systems * **Audit & Compliance**: Track access and changes to secrets * **Rotation Support**: Easily rotate credentials without updating flows * **Access Control**: Use your existing secret manager access policies ## Supported Providers * **[HashiCorp Vault](./hashicorp)** - Enterprise-grade secrets management * **[CyberArk Conjur](./cyberark-conjur)** - Centralized secrets management with host-based authentication * **[AWS Secrets Manager](./aws)** - Managed secrets storage on AWS * **[1Password](./1password)** - Consumer and team password manager with Secrets Automation ## How to Connect 1. Go to **Platform Admin → Security → Secret Managers** 2. Select the secret manager provider you want to connect 3. Follow the provider-specific setup instructions in the provider documentation 4. Enter the required connection details 5. Click **Connect** to test and save the connection The connection will be encrypted and stored securely. You can disconnect at any time by clicking the **Remove** button. ## Using Secret Managers in Global Connections Once connected, you can use secret managers when creating or editing global connections: 1. When configuring a global connection that requires credentials (like API keys or passwords) 2. Click the **key icon** (🔑) next to the input field 3. Select your secret manager provider from the dropdown 4. Enter the secret path/identifier required by your provider (see provider-specific documentation) 5. The connection will automatically retrieve the secret from your secret manager when needed Manage Oauth2 apps ## How It Works When you use a secret manager in a connection: * The global connection stores a reference to the secret (not the actual credential) * When the flow runs, Activepieces authenticates with your secret manager and retrieves the secret * Secrets are fetched on-demand and never stored in Activepieces * If the secret is updated in your secret manager, flows will use the new value after the cache expires (up to 1 hour), or immediately after clearing the cache ## Caching Connection checks and retrieved secrets are cached in redis encrypted for **1 hour** to reduce latency and provider API load. To force a refresh (e.g. after rotating credentials or updating secrets), platform admins can clear the cache in the secret managers setup page Clear secret manager cache or by calling the endpoint ``` curl --request DELETE \ --url https:///api/v1/secret-managers/cache \ --header 'Authorization: Bearer ' ``` ## Security Considerations * **Encryption**: Secret managers authentication configuration is encrypted * **Access Control**: Use your secret manager's access policies to control who can access secrets * **Network Security**: Ensure your secret manager is accessible from your Activepieces instance * **Credential Management**: Regularly rotate authentication credentials for secret managers ## Troubleshooting **Connection Failed:** * Verify the connection details are correct and accessible * Check that authentication credentials are valid * Ensure network connectivity between Activepieces and your secret manager * Review provider-specific troubleshooting guides **Secret Not Found:** * Verify the secret path/name is correct * Check that the secret exists in your secret manager * Ensure the authentication credentials have permissions to read the secret **Permission Denied:** * Verify the authentication credentials have the necessary permissions * Check your secret manager's access control policies * Review audit logs in your secret manager for detailed error information # Setup AI Providers Source: https://www.activepieces.com/docs/admin-guide/guides/setup-ai-providers AI providers are configured by the platform admin to centrally manage credentials and access, making [AI pieces](https://www.activepieces.com/pieces/ai) and their features available to everyone in all projects. ## Supported Providers * **OpenAI** * **Anthropic** * **Gemini** * **Vercel AI Gateway** * **Cloudflare AI Gateway** ## How to Setup Go to **Admin Console** → **AI** page. Add your provider's base URL and API key. These settings apply to all projects. Manage AI Providers ## Cost Control & Logging Use an AI gateway like **Vercel AI Gateway** or **Cloudflare AI Gateway** to: * Set rate limits and budgets * Log and monitor all AI requests * Track usage across projects Just set the gateway URL as your provider's base URL in the Admin Console. # How to Setup SSO Source: https://www.activepieces.com/docs/admin-guide/guides/sso Configure Single Sign-On (SSO) to enable secure, centralized authentication for your Activepieces platform ## Overview Single Sign-On (SSO) allows your team to authenticate using your organization's existing identity provider, eliminating the need for separate Activepieces credentials. This improves security, simplifies user management, and provides a seamless login experience. ## Prerequisites Before configuring SSO, ensure you have: * **Admin access** to your Activepieces platform * **Admin access** to your identity provider (Google, GitHub, Okta, or JumpCloud) * The **redirect URL** from your Activepieces SSO configuration screen ## Accessing SSO Configuration Navigate to **Platform Settings** → **SSO** in your Activepieces admin dashboard to access the SSO configuration screen. SSO Configuration ## Enforcing SSO You can enforce SSO by specifying your organization's email domain. When SSO enforcement is enabled: * Users with matching email domains must authenticate through the SSO provider * Email/password login can be disabled for enhanced security * All authentication is routed through your designated identity provider We recommend testing SSO with a small group of users before enforcing it organization-wide. ## Supported SSO Providers Activepieces supports multiple SSO providers to integrate with your existing identity management system. ### Google Go to the [Google Cloud Console](https://console.cloud.google.com/) and select your project (or create a new one). Navigate to **APIs & Services** → **Credentials** → **Create Credentials** → **OAuth client ID**. Select **Web application** as the application type. Copy the **Redirect URL** from the Activepieces SSO configuration screen and add it to the **Authorized redirect URIs** in Google Cloud Console. Copy the **Client ID** and **Client Secret** from Google and paste them into the corresponding fields in Activepieces. Click **Finish** to complete the setup. ### GitHub Go to [GitHub Developer Settings](https://github.com/settings/developers) → **OAuth Apps** → **New OAuth App**. Fill in the application details: * **Application name**: Choose a recognizable name (e.g., "Activepieces SSO") * **Homepage URL**: Enter your Activepieces instance URL Copy the **Redirect URL** from the Activepieces SSO configuration screen and paste it into the **Authorization callback URL** field. Click **Register application** to create the OAuth App. After registration, click **Generate a new client secret** and copy it immediately (it won't be shown again). Copy the **Client ID** and **Client Secret** and paste them into the corresponding fields in Activepieces. Click **Finish** to complete the setup. ### SAML with Okta Go to the [Okta Admin Portal](https://login.okta.com/) → **Applications** → **Create App Integration**. Choose **SAML 2.0** as the sign-on method and click **Next**. Enter an **App name** (e.g., "Activepieces") and optionally upload a logo. Click **Next**. * **Single sign-on URL**: Copy the SSO URL from the Activepieces configuration screen * **Audience URI (SP Entity ID)**: Enter `Activepieces` * **Name ID format**: Select `EmailAddress` Add the following attribute mappings: | Name | Value | | ----------- | ---------------- | | `firstName` | `user.firstName` | | `lastName` | `user.lastName` | | `email` | `user.email` | Click **Next**, select the appropriate feedback option, and click **Finish**. Go to the **Sign On** tab → **View SAML setup instructions** or **View IdP metadata**. Copy the Identity Provider metadata XML. * Paste the **IdP Metadata** XML into the corresponding field * Copy the **X.509 Certificate** from Okta and paste it into the **Signing Key** field Click **Save** to complete the setup. ### SAML with JumpCloud Go to the [JumpCloud Admin Portal](https://console.jumpcloud.com/) → **SSO Applications** → **Add New Application** → **Custom SAML App**. Copy the **ACS URL** from the Activepieces configuration screen and paste it into the **ACS URLs** field in JumpCloud. JumpCloud ACS URL Set the **SP Entity ID** (Audience URI) to `Activepieces`. Configure the following attribute mappings: | Service Provider Attribute | JumpCloud Attribute | | -------------------------- | ------------------- | | `firstName` | `firstname` | | `lastName` | `lastname` | | `email` | `email` | JumpCloud User Attributes JumpCloud does not include the `HTTP-Redirect` binding by default. You **must** enable this option. JumpCloud Redirect Binding Without HTTP-Redirect binding, the SSO integration will not work correctly. Click **Save**, then refresh the page and click **Export Metadata**. JumpCloud Export Metadata Verify that the exported XML contains `Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"` to ensure the binding was properly enabled. Paste the exported metadata XML into the **IdP Metadata** field in Activepieces. Locate the `` element in the IdP metadata and extract its value. Format it as a PEM certificate: ``` -----BEGIN CERTIFICATE----- [PASTE THE CERTIFICATE VALUE HERE] -----END CERTIFICATE----- ``` Paste this into the **Signing Key** field. In JumpCloud, assign the application to the appropriate users or user groups. JumpCloud Assign App Click **Finish** to complete the setup. ## Troubleshooting * Verify the redirect URL is correctly configured in your identity provider * Ensure users are assigned to the application in your identity provider * Check that email domains match the SSO enforcement settings * Confirm the IdP metadata is complete and correctly formatted * Verify the signing certificate is properly formatted with BEGIN/END markers * Ensure all required attributes (firstName, lastName, email) are mapped * Enable the HTTP-Redirect binding option in JumpCloud * Re-export the metadata after enabling the binding * Verify the binding appears in the exported XML ## Need Help? If you encounter issues during SSO setup, please contact our enterprise support or [sales team](https://www.activepieces.com/sales). # How to Structure Projects Source: https://www.activepieces.com/docs/admin-guide/guides/structure-projects Projects in Activepieces are the main units for organizing your automations and resources within your organization. Every project contains its own flows, connections, and tables. Access to these resources is shared among everyone who has access to that project. There are two types of projects: * **Personal Projects**: Each user invited to your organization automatically receives a personal project. This is a private space where only that user can create and manage flows, connections, and tables. * **Team Projects**: Team projects are shared spaces that can be created and managed from this page. Multiple users can be invited to a team project, allowing them to collaborate, share access to flows, connections, and tables, and work together. When organizing your work, create team projects for group collaboration and utilize personal projects for individual or private tasks. # Connection Deleted Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/connection-deleted # Connection Upserted Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/connection-upserted # Flow Created Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/flow-created # Flow Deleted Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/flow-deleted # Flow Run Finished Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/flow-run-finished # Flow Run Started Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/flow-run-started # Flow Updated Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/flow-updated # Folder Created Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/folder-created # Folder Deleted Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/folder-deleted # Folder Updated Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/folder-updated # Overview Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/overview This table in admin console contains all application events. We are constantly adding new events, so there is no better place to see the events defined in the code than [here](https://github.com/activepieces/activepieces/blob/main/packages/shared/src/lib/ee/audit-events/index.ts). Audit Logs # Signing Key Created Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/signing-key-created # User Email Verified Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/user-email-verified # User Password Reset Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/user-password-reset # User Signed In Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/user-signed-in # User Signed Up Source: https://www.activepieces.com/docs/admin-guide/security/audit-logs/user-signed-up # Security & Data Practices Source: https://www.activepieces.com/docs/admin-guide/security/practices We prioritize security and follow these practices to keep information safe. ## External Systems Credentials **Storing Credentials** All credentials are stored with 256-bit encryption keys, and there is no API to retrieve them for the user. They are sent only during processing, after which access is revoked from the engine. **Data Masking** We implement a robust data masking mechanism where third-party credentials or any sensitive information are systematically censored within the logs, guaranteeing that sensitive information is never stored or documented. **OAuth2** Integrations with third parties are always done using OAuth2, with a limited number of scopes when third-party support allows. ## Vulnerability Disclosure Activepieces is an open-source project that welcomes contributors to test and report security issues. For detailed information about our security policy, please refer to our GitHub Security Policy at: [https://github.com/activepieces/activepieces/security/policy](https://github.com/activepieces/activepieces/security/policy) ## Access and Authentication **Role-Based Access Control (RBAC)** To manage user access, we utilize Role-Based Access Control (RBAC). Team admins assign roles to users, granting them specific permissions to access and interact with projects, folders, and resources. RBAC allows for fine-grained control, enabling administrators to define and enforce access policies based on user roles. **Single Sign-On (SSO)** Implementing Single Sign-On (SSO) serves as a pivotal component of our security strategy. SSO streamlines user authentication by allowing them to access Activepieces with a single set of credentials. This not only enhances user convenience but also strengthens security by reducing the potential attack surface associated with managing multiple login credentials. **Audit Logs** We maintain comprehensive audit logs to track and monitor all access activities within Activepieces. This includes user interactions, system changes, and other relevant events. Our meticulous logging helps identify security threats and ensures transparency and accountability in our security measures. **Password Policy Enforcement** Users log in to Activepieces using a password known only to them. Activepieces enforces password length and complexity standards. Passwords are not stored; instead, only a secure hash of the password is stored in the database. For more information. ## Privacy & Data **Supported Cloud Regions** Presently, our cloud services are available in Germany as the supported data region. We have plans to expand to additional regions in the near future. If you opt for **self-hosting**, the available regions will depend on where you choose to host. **Policy** To better understand how we handle your data and prioritize your privacy, please take a moment to review our [Privacy Policy](https://www.activepieces.com/privacy). This document outlines in detail the measures we take to safeguard your information and the principles guiding our approach to privacy and data protection. # Create Action Source: https://www.activepieces.com/docs/build-pieces/building-pieces/create-action ## Action Definition Now let's create first action which fetch random ice-cream flavor. ```bash theme={null} npm run cli actions create ``` You will be asked three questions to define your new piece: 1. `Piece Folder Name`: This is the name associated with the folder where the action resides. It helps organize and categorize actions within the piece. 2. `Action Display Name`: The name users see in the interface, conveying the action's purpose clearly. 3. `Action Description`: A brief, informative text in the UI, guiding users about the action's function and purpose. Next, let's create the action file: **Example:** ```bash theme={null} npm run cli actions create ? Enter the piece folder name : gelato ? Enter the action display name : get icecream flavor ? Enter the action description : fetches random icecream flavor. ``` This will create a new TypeScript file named `get-icecream-flavor.ts` in the `packages/pieces/community/gelato/src/lib/actions` directory. Inside this file, paste the following code: ```typescript theme={null} import { createAction, Property, PieceAuth, } from '@activepieces/pieces-framework'; import { httpClient, HttpMethod } from '@activepieces/pieces-common'; import { gelatoAuth } from '../..'; export const getIcecreamFlavor = createAction({ name: 'get_icecream_flavor', // Must be a unique across the piece, this shouldn't be changed. auth: gelatoAuth, displayName: 'Get Icecream Flavor', description: 'Fetches random icecream flavor', props: {}, async run(context) { const res = await httpClient.sendRequest({ method: HttpMethod.GET, url: 'https://cloud.activepieces.com/api/v1/webhooks/RGjv57ex3RAHOgs0YK6Ja/sync', headers: { Authorization: context.auth, // Pass API key in headers }, }); return res.body; }, }); ``` The createAction function takes an object with several properties, including the `name`, `displayName`, `description`, `props`, and `run` function of the action. The `name` property is a unique identifier for the action. The `displayName` and `description` properties are used to provide a human-readable name and description for the action. The `props` property is an object that defines the properties that the action requires from the user. In this case, the action doesn't require any properties. The `run` function is the function that is called when the action is executed. It takes a single argument, context, which contains the values of the action's properties. The `run` function utilizes the httpClient.sendRequest function to make a GET request, fetching a random ice cream flavor. It incorporates API key authentication in the request headers. Finally, it returns the response body. ## Expose The Definition To make the action readable by Activepieces, add it to the array of actions in the piece definition. ```typescript theme={null} import { createPiece } from '@activepieces/pieces-framework'; // Don't forget to add the following import. import { getIcecreamFlavor } from './lib/actions/get-icecream-flavor'; export const gelato = createPiece({ displayName: 'Gelato', logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png', authors: [], auth: gelatoAuth, // Add the action here. actions: [getIcecreamFlavor], // <-------- triggers: [], }); ``` # Testing By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`. For more details, check out the [Piece Development](./development-setup) section. Once you edit the environment variable, restart the backend. The piece will be rebuilt. After this process, you'll need to **refresh** the frontend to see the changes. If the build fails, try debugging by running `npx turbo run build --filter=@activepieces/piece-gelato`. It will display any errors in your code. To test the action, use the flow builder in Activepieces. It should function as shown in the screenshot. Gelato Action # Create Trigger Source: https://www.activepieces.com/docs/build-pieces/building-pieces/create-trigger This tutorial will guide you through the process of creating trigger for a Gelato piece that fetches new icecream flavor. ## Trigger Definition To create trigger run the following command, ```bash theme={null} npm run cli triggers create ``` 1. `Piece Folder Name`: This is the name associated with the folder where the trigger resides. It helps organize and categorize triggers within the piece. 2. `Trigger Display Name`: The name users see in the interface, conveying the trigger's purpose clearly. 3. `Trigger Description`: A brief, informative text in the UI, guiding users about the trigger's function and purpose. 4. `Trigger Technique`: Specifies the trigger type - either [polling](../piece-reference/triggers/polling-trigger) or [webhook](../piece-reference/triggers/webhook-trigger). **Example:** ```bash theme={null} npm run cli triggers create ? Enter the piece folder name : gelato ? Enter the trigger display name : new flavor created ? Enter the trigger description : triggers when a new icecream flavor is created. ? Select the trigger technique: polling ``` This will create a new TypeScript file at `packages/pieces/community/gelato/src/lib/triggers` named `new-flavor-created.ts`. Inside this file, paste the following code: ```ts theme={null} import { gelatoAuth } from '../../'; import { DedupeStrategy, HttpMethod, HttpRequest, Polling, httpClient, pollingHelper, } from '@activepieces/pieces-common'; import { PiecePropValueSchema, TriggerStrategy, createTrigger, } from '@activepieces/pieces-framework'; import dayjs from 'dayjs'; const polling: Polling< PiecePropValueSchema, Record > = { strategy: DedupeStrategy.TIMEBASED, items: async ({ auth, propsValue, lastFetchEpochMS }) => { const request: HttpRequest = { method: HttpMethod.GET, url: 'https://cloud.activepieces.com/api/v1/webhooks/aHlEaNLc6vcF1nY2XJ2ed/sync', headers: { authorization: auth, }, }; const res = await httpClient.sendRequest(request); return res.body['flavors'].map((flavor: string) => ({ epochMilliSeconds: dayjs().valueOf(), data: flavor, })); }, }; export const newFlavorCreated = createTrigger({ auth: gelatoAuth, name: 'newFlavorCreated', displayName: 'new flavor created', description: 'triggers when a new icecream flavor is created.', props: {}, sampleData: {}, type: TriggerStrategy.POLLING, async test(context) { return await pollingHelper.test(polling, context); }, async onEnable(context) { const { store, auth, propsValue } = context; await pollingHelper.onEnable(polling, { store, auth, propsValue }); }, async onDisable(context) { const { store, auth, propsValue } = context; await pollingHelper.onDisable(polling, { store, auth, propsValue }); }, async run(context) { return await pollingHelper.poll(polling, context); }, }); ``` The way polling triggers usually work is as follows: `Run`:The run method executes every 5 minutes, fetching data from the endpoint within a specified timestamp range or continuing until it identifies the last item ID. It then returns the new items as an array. In this example, the httpClient.sendRequest method is utilized to retrieve new flavors, which are subsequently stored in the store along with a timestamp. ## Expose The Definition To make the trigger readable by Activepieces, add it to the array of triggers in the piece definition. ```typescript theme={null} import { createPiece } from '@activepieces/pieces-framework'; import { getIcecreamFlavor } from './lib/actions/get-icecream-flavor'; // Don't forget to add the following import. import { newFlavorCreated } from './lib/triggers/new-flavor-created'; export const gelato = createPiece({ displayName: 'Gelato Tutorial', logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png', authors: [], auth: gelatoAuth, actions: [getIcecreamFlavor], // Add the trigger here. triggers: [newFlavorCreated], // <-------- }); ``` # Testing By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`. For more details, check out the [Piece Development](./development-setup) section. Once you edit the environment variable, restart the backend. The piece will be rebuilt. After this process, you'll need to **refresh** the frontend to see the changes. To test the trigger, use the load sample data from flow builder in Activepieces. It should function as shown in the screenshot. To make your webhook accessible from the internet, you need to expose your local development instance to the internet, do the following: 1. Install [localxpose](https://localxpose.io/docs#start-your-first-tunnel). 2. Follow the documentation to start your first tunnel to localhost:4200. 3. Copy the tunnel domain, i.e wozcsvaint.loclx.io, and replace the `AP_FRONTEND_URL` environment variable in `packages/server/api/.env` with the exposed url, i.e [https://wozcsvaint.loclx.io](https://wozcsvaint.loclx.io) 4. Go to /packages/web/vite.config.ts, uncomment allowedHosts and replace the value with the same tunnel domain, i.e wozcsvaint.loclx.io. Once you have completed these configurations, you will be able to test webhook triggers and run published flows that have them. Gelato Action # Development setup Source: https://www.activepieces.com/docs/build-pieces/building-pieces/development-setup ## Prerequisites * Node.js v18+ * npm v9+ ## Instructions 1. Setup the environment ```bash theme={null} node tools/setup-dev.js ``` 2. Start the environment This command will start activepieces with sqlite3 and in memory queue. ```bash theme={null} npm start ``` By default, the development setup only builds specific pieces.Open the file `packages/server/api/.env` and add comma-separated list of pieces to make available. For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section. 3. Go to ***localhost:4200*** on your web browser and sign in with these details: Email: `dev@ap.com` Password: `12345678` ## Pieces Development When [`AP_SYNC_MODE`](https://github.com/activepieces/activepieces/blob/main/packages/server/api/.env#L17) is set to `OFFICIAL_AUTO`, all pieces are automatically loaded from the cloud API and synced to the database on first launch. This process may take a few seconds to several minutes depending on your internet connection. For local development, pieces are loaded from your local `dist` folder instead of the database. To enable this, set the [`AP_DEV_PIECES`](https://github.com/activepieces/activepieces/blob/main/packages/server/api/.env#L4) environment variable with a comma-separated list of pieces. For example, to develop with `google-sheets` and `cal-com`: ```sh theme={null} AP_DEV_PIECES=google-sheets,cal-com npm start ``` # Overview Source: https://www.activepieces.com/docs/build-pieces/building-pieces/overview This section helps developers build and contribute pieces. Building pieces is fun and important; it allows you to customize Activepieces for your own needs. We love contributions! In fact, most of the pieces are contributed by the community. Feel free to open a pull request. **Friendly Tip:** For the fastest support, we recommend joining our Discord community. We are dedicated to addressing every question and concern raised there. Build pieces using TypeScript for a more powerful and flexible development process. See your changes in the browser within 7 seconds. Work within the open-source environment, explore, and contribute to other pieces. Join our large community, where you can ask questions, share ideas, and develop alongside others. # Add Piece Authentication Source: https://www.activepieces.com/docs/build-pieces/building-pieces/piece-authentication ### Piece Authentication Activepieces supports multiple forms of authentication, you can check those forms [here](../piece-reference/authentication) Now, let's establish authentication for this piece, which necessitates the inclusion of an API Key in the headers. Modify `src/index.ts` file to add authentication, ```ts theme={null} import { PieceAuth, createPiece } from '@activepieces/pieces-framework'; export const gelatoAuth = PieceAuth.SecretText({ displayName: 'API Key', required: true, description: 'Please use **test-key** as value for API Key', }); export const gelato = createPiece({ displayName: 'Gelato', logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png', auth: gelatoAuth, authors: [], actions: [], triggers: [], }); ``` Use the value **test-key** as the API key when testing actions or triggers for Gelato. # Create Piece Definition Source: https://www.activepieces.com/docs/build-pieces/building-pieces/piece-definition This tutorial will guide you through the process of creating a Gelato piece with an action that fetches random icecream flavor and trigger that fetches new icecream flavor created. It assumes that you are familiar with the following: * [Activepieces Local development](./development-setup) Or [GitHub Codespaces](../misc/codespaces). * TypeScript syntax. ## Piece Definition To get started, let's generate a new piece for Gelato ```bash theme={null} npm run cli pieces create ``` You will be asked three questions to define your new piece: 1. `Piece Name`: Specify a name for your piece. This name uniquely identifies your piece within the ActivePieces ecosystem. 2. `Package Name`: Optionally, you can enter a name for the npm package associated with your piece. If left blank, the default name will be used. 3. `Piece Type`: Choose the piece type based on your intention. It can be either "custom" if it's a tailored solution for your needs, or "community" if it's designed to be shared and used by the broader community. **Example:** ```bash theme={null} npm run cli pieces create ? Enter the piece name: gelato ? Enter the package name: @activepieces/piece-gelato ? Select the piece type: community ``` The piece will be generated at `packages/pieces/community/gelato/`, the `src/index.ts` file should contain the following code ```ts theme={null} import { PieceAuth, createPiece } from '@activepieces/pieces-framework'; export const gelato = createPiece({ displayName: 'Gelato', logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png', auth: PieceAuth.None(), authors: [], actions: [], triggers: [], }); ``` # Fork Repository Source: https://www.activepieces.com/docs/build-pieces/building-pieces/setup-fork To start building pieces, we need to fork the repository that contains the framework library and the development environment. Later, we will publish these pieces as `npm` artifacts. Follow these steps to fork the repository: If you are on windows, please install [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) and set up git there then proceed with the instructions down below 1. Go to the repository page at [https://github.com/activepieces/activepieces](https://github.com/activepieces/activepieces). 2. Click the `Fork` button located in the top right corner of the page. Fork Repository 3. Clone your fork using a shallow clone for faster setup: ```bash theme={null} git clone --depth=1 https://github.com/YOUR_USERNAME/activepieces.git ``` Using `--depth=1` reduces the clone size significantly by only fetching the latest commit instead of the full history. If you are an enterprise customer and want to use the private pieces feature, you can refer to the tutorial on how to set up a [private fork](../misc/private-fork). # Start Building Source: https://www.activepieces.com/docs/build-pieces/building-pieces/start-building This section guides you in creating a Gelato piece, from setting up your development environment to contributing the piece. By the end of this tutorial, you will have a piece with an action that fetches a random ice cream flavor and a trigger that fetches newly created ice cream flavors. These are the next sections. In each step, we will do one small thing. This tutorial should take around 30 minutes. ## Steps Overview Fork the repository to create your own copy of the codebase. Set up your development environment with the necessary tools and dependencies. Define the structure and behavior of your Gelato piece. Implement authentication mechanisms for your Gelato piece. Create an action that fetches a random ice cream flavor. Create a trigger that fetches newly created ice cream flavors. Share your Gelato piece with others. Contribute a piece to our repo and receive +1,400 tasks/month on [Activepieces Cloud](https://cloud.activepieces.com). # Build Custom Pieces Source: https://www.activepieces.com/docs/build-pieces/misc/build-piece You can use the CLI to build custom pieces for the platform. This process compiles the pieces and exports them as a `.tgz` packed archive. ### How It Works The CLI scans the `packages/pieces/` directory for the specified piece. It checks the **name** in the `package.json` file. If the piece is found, it builds and packages it into a `.tgz` archive. ### Usage To build a piece, follow these steps: 1. Ensure you have the CLI installed by cloning the repository. 2. Run the following command: ```bash theme={null} npm run build-piece ``` You will be prompted to enter the name of the piece you want to build. For example: ```bash theme={null} ? Enter the piece folder name : google-drive ``` The CLI will build the piece and you will be given the path to the archive. For example: ```bash theme={null} Piece 'google-drive' built and packed successfully at packages/pieces/community/google-drive/dist ``` You may also build the piece non-interactively by passing the piece name as an argument. For example: ```bash theme={null} npm run build-piece google-drive ``` # GitHub Codespaces Source: https://www.activepieces.com/docs/build-pieces/misc/codespaces GitHub Codespaces is a cloud development platform that enables developers to write, run, and debug code directly in their browsers, seamlessly integrated with GitHub. ### Steps to setup Codespaces 1. Go to [Activepieces repo](https://github.com/activepieces/activepieces). 2. Click Code `<>`, then under codespaces click create codespace on main. Create Codespace By default, the development setup only builds specific pieces.Open the file `packages/server/api/.env` and add comma-separated list of pieces to make available. For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section. 3. Open the terminal and run `npm start` 4. Access the frontend URL by opening port 4200 and signing in with these details: Email: `dev@ap.com` Password: `12345678` # Dev Containers Source: https://www.activepieces.com/docs/build-pieces/misc/dev-container ## Using Dev Containers in Visual Studio Code The project includes a dev container configuration that allows you to use Visual Studio Code's [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension to develop the project in a consistent environment. This can be especially helpful if you are new to the project or if you have a different environment setup on your local machine. ## Prerequisites Before you can use the dev container, you will need to install the following: * [Visual Studio Code](https://code.visualstudio.com/). * The [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension for Visual Studio Code. * [Docker](https://www.docker.com/). ## Using the Dev Container To use the dev container for the Activepieces project, follow these steps: 1. Clone the Activepieces repository to your local machine. 2. Open the project in Visual Studio Code. 3. Press `Ctrl+Shift+P` and type `> Dev Containers: Reopen in Container`. 4. Run `npm start`. 5. The backend will run at `localhost:3000` and the frontend will run at `localhost:4200`. By default, the development setup only builds specific pieces.Open the file `packages/server/api/.env` and add comma-separated list of pieces to make available. For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section. The login credentials are:\ Email: `dev@ap.com` Password: `12345678` ## Exiting the Dev Container To exit the dev container and return to your local environment, follow these steps: 1. In the bottom left corner of Visual Studio Code, click the `Remote-Containers: Reopen folder locally` button. 2. Visual Studio Code will close the connection to the dev container and reopen the project in your local environment. ## Troubleshoot One of the best trouble shoot after an error occur is to reset the dev container. 1. Exit the dev container 2. Run the following ```sh theme={null} sh tools/reset-dev.sh ``` 3. Rebuild the dev container from above steps # Migrate from Nx to Turbo Source: https://www.activepieces.com/docs/build-pieces/misc/migrate-nx-to-turbo The Activepieces monorepo has fully migrated to Turbo. This guide is kept for **historical reference** and for users with older forks that still use the Nx-based build system. If you have an existing fork with custom pieces built using the **old Nx-based build system**, you need to migrate them to the new **Turbo-based build system**. This guide explains what changed and provides a migration script. ## What Changed The Activepieces monorepo replaced [Nx](https://nx.dev) with [Turbo](https://turbo.build) as its build orchestrator. For pieces, this means: | | **Old (Nx)** | **New (Turbo)** | | ---------------- | -------------------------- | ---------------------------------------------------------- | | Build config | `project.json` per piece | `package.json` scripts | | Build command | `nx build pieces-{name}` | `turbo run build --filter=@activepieces/piece-{name}` | | Output directory | `dist/out-tsc` (shared) | `./dist` (local per piece) | | Task runner | Nx executor (`@nx/js:tsc`) | Direct `tsc -p tsconfig.lib.json && cp package.json dist/` | | Dependencies | Inferred by Nx graph | Workspace protocol (`workspace:*`) in `package.json` | ### Files affected per piece * **`project.json`** — Deleted (no longer needed) * **`package.json`** — Added `build` and `lint` scripts, added `main` and `types` fields, added workspace dependencies * **`tsconfig.lib.json`** — Updated `outDir`, added `rootDir`, `baseUrl`, `paths` ## Automatic Migration Run the migration script to update all custom pieces at once: ```bash theme={null} npx ts-node tools/scripts/migrate-custom-piece-to-turbo.ts ``` This scans `packages/pieces/custom/` and applies all necessary changes. ### Migrate a specific piece You can also pass a path to migrate a single piece: ```bash theme={null} npx ts-node tools/scripts/migrate-custom-piece-to-turbo.ts packages/pieces/custom/my-piece ``` ### What the script does For each piece, the script: 1. **Updates `package.json`** — adds `build` and `lint` scripts, sets `main` and `types` entry points, ensures `@activepieces/pieces-framework`, `@activepieces/shared`, and `tslib` are listed as dependencies 2. **Updates `tsconfig.lib.json`** — sets `outDir` to `./dist`, adds `rootDir`, `baseUrl`, `paths`, and `declaration` settings 3. **Creates `tsconfig.json`** if missing — extends the root `tsconfig.base.json` 4. **Deletes `project.json`** — removes Nx configuration ## Verify the Migration After migrating, build your piece to verify everything works: ```bash theme={null} npx turbo run build --filter=@activepieces/piece-your-piece --force ``` Or use the CLI: ```bash theme={null} npm run build-piece your-piece ``` The build output should appear in `packages/pieces/custom/your-piece/dist/`. # Custom Pieces CI/CD Source: https://www.activepieces.com/docs/build-pieces/misc/pieces-ci-cd You can use the CLI to sync custom pieces. There is no need to rebuild the Docker image as they are loaded directly from npm. ### How It Works Use the CLI to sync items from `packages/pieces/custom/` to instances. In production, Activepieces acts as an npm registry, storing all piece versions. The CLI scans the directory for `package.json` files, checking the **name** and **version** of each piece. If a piece isn't uploaded, it packages and uploads it via the API. ### Usage To use the CLI, follow these steps: 1. Generate an API Key from the Admin Interface. Go to Settings and generate the API Key. 2. Install the CLI by cloning the repository. 3. Run the following command, replacing `API_KEY` with your generated API Key and `INSTANCE_URL` with your instance URL: ```bash theme={null} AP_API_KEY=your_api_key_here bun run sync-pieces -- --apiUrl https://INSTANCE_URL/api ``` ### Developer Workflow 1. Developers create and modify the pieces offline. 2. Increment the piece version in their corresponding `package.json`. For more information, refer to the [piece versioning](../piece-reference/piece-versioning) documentation. 3. Open a pull request towards the main branch. 4. Once the pull request is merged to the main branch, manually run the CLI or use a GitHub/GitLab Action to trigger the synchronization process. ### GitHub Action ```yaml theme={null} name: Sync Custom Pieces on: push: branches: - main workflow_dispatch: jobs: sync-pieces: runs-on: ubuntu-latest steps: # Step 1: Check out the repository code with full history - name: Check out repository code uses: actions/checkout@v3 with: fetch-depth: 0 # Step 2: Set up Bun - name: Set up Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest # Step 3: Cache Bun dependencies - name: Cache Bun dependencies uses: actions/cache@v3 with: path: ~/.bun/install/cache key: bun-${{ hashFiles('bun.lockb') }} restore-keys: | bun- # Step 4: Install dependencies using Bun - name: Install dependencies run: bun install --no-save # Step 5: Sync Custom Pieces - name: Sync Custom Pieces env: AP_API_KEY: ${{ secrets.AP_API_KEY }} run: bun run sync-pieces -- --apiUrl ${{ secrets.INSTANCE_URL }}/api ``` # Setup Private Fork Source: https://www.activepieces.com/docs/build-pieces/misc/private-fork **Friendly Tip #1:** If you want to experiment, you can fork or clone the public repository. For private piece installation, you will need the paid edition. However, you can still develop pieces, contribute them back, **OR** publish them to the public npm registry and use them in your own instance or project. ## Create a Private Fork (Private Pieces) By following these steps, you can create a private fork on GitHub, GitLab or another platform and configure the "activepieces" repository as the upstream source, allowing you to incorporate changes from the "activepieces" repository. 1. **Clone the Repository:** Begin by creating a bare clone of the repository. Remember that this is a temporary step and will be deleted later. ```bash theme={null} git clone --bare git@github.com:activepieces/activepieces.git ``` 2. **Create a Private Git Repository** Generate a new private repository on GitHub or your chosen platform. When initializing the new repository, do not include a README, license, or gitignore files. This precaution is essential to avoid merge conflicts when synchronizing your fork with the original repository. 3. **Mirror-Push to the Private Repository:** Mirror-push the bare clone you created earlier to your newly created "activepieces" repository. Make sure to replace `` in the URL below with your actual GitHub username. ```bash theme={null} cd activepieces.git git push --mirror git@github.com:/activepieces.git ``` 4. **Remove the Temporary Local Repository:** ```bash theme={null} cd .. rm -rf activepieces.git ``` 5. **Clone Your Private Repository:** Now, you can clone your "activepieces" repository onto your local machine into your desired directory. ```bash theme={null} cd ~/path/to/directory git clone git@github.com:/activepieces.git ``` 6. **Add the Original Repository as a Remote:** If desired, you can add the original repository as a remote to fetch potential future changes. However, remember to disable push operations for this remote, as you are not permitted to push changes to it. ```bash theme={null} git remote add upstream git@github.com:activepieces/activepieces.git git remote set-url --push upstream DISABLE ``` You can view a list of all your remotes using `git remote -v`. It should resemble the following: ``` origin git@github.com:/activepieces.git (fetch) origin git@github.com:/activepieces.git (push) upstream git@github.com:activepieces/activepieces.git (fetch) upstream DISABLE (push) ``` > When pushing changes, always use `git push origin`. ### Sync Your Fork To retrieve changes from the "upstream" repository, fetch the remote and rebase your work on top of it. ```bash theme={null} git fetch upstream git merge upstream/main ``` Conflict resolution should not be necessary since you've only added pieces to your repository. # Publish Custom Pieces Source: https://www.activepieces.com/docs/build-pieces/misc/publish-piece You can use the CLI to publish custom pieces to the platform. This process packages the pieces and uploads them to the specified API endpoint. ### How It Works The CLI scans the `packages/pieces/` directory for the specified piece. It checks the **name** and **version** in the `package.json` file. If the piece is not already published, it builds, packages, and uploads it to the platform using the API. ### Usage To publish a piece, follow these steps: 1. Ensure you have an API Key. Generate it from the Admin Interface by navigating to Settings. 2. Install the CLI by cloning the repository. 3. Run the following command: ```bash theme={null} npm run publish-piece-to-api ``` 4. You will be asked three questions to publish your piece: * `Piece Folder Name`: This is the name associated with the folder where the action resides. It helps organize and categorize actions within the piece. * `API URL`: This is the URL of the API endpoint where the piece will be published (ex: [https://cloud.activepieces.com/api](https://cloud.activepieces.com/api)). * `API Key Source`: This is the source of the API key. It can be either `Env Variable (AP_API_KEY)` or `Manually`. In case you choose `Env Variable (AP_API_KEY)`, the CLI will use the API key from the `.env` file in the `packages/server/api` directory. In case you choose `Manually`, you will be asked to enter the API key. Examples: ```bash theme={null} npm run publish-piece-to-api ? Enter the piece folder name : google-drive ? Enter the API URL : https://cloud.activepieces.com/api ? Enter the API Key Source : Env Variable (AP_API_KEY) ``` ```bash theme={null} npm run publish-piece-to-api ? Enter the piece folder name : google-drive ? Enter the API URL : https://cloud.activepieces.com/api ? Enter the API Key Source : Manually ? Enter the API Key : ap_1234567890abcdef1234567890abcdef ``` # Testing Pieces Source: https://www.activepieces.com/docs/build-pieces/misc/testing-pieces How to add unit tests to your pieces Testing pieces is **optional** but recommended for complex logic. Pieces can be tested using [Vitest](https://vitest.dev/) with the `createMockActionContext` helper from the framework. For a full working example, see the [text-helper piece tests on GitHub](https://github.com/activepieces/activepieces/tree/main/packages/pieces/core/text-helper/test). ## Setup ### 1. Add vitest to your piece Add `vitest` as a dev dependency in your piece's `package.json` and add a `test` script: ```json theme={null} { "scripts": { "build": "tsc -p tsconfig.lib.json && cp package.json dist/", "lint": "eslint 'src/**/*.ts'", "test": "vitest run" }, "devDependencies": { "vitest": "3.0.8" } } ``` ### 2. Create a vitest config Create `vitest.config.ts` in your piece root: ```typescript theme={null} import path from 'path' import { defineConfig } from 'vitest/config' const repoRoot = path.resolve(__dirname, '../../../..') export default defineConfig({ test: { globals: true, environment: 'node', }, resolve: { alias: { '@activepieces/shared': path.resolve(repoRoot, 'packages/shared/src/index.ts'), '@activepieces/pieces-framework': path.resolve(repoRoot, 'packages/pieces/framework/src/index.ts'), '@activepieces/pieces-common': path.resolve(repoRoot, 'packages/pieces/common/src/index.ts'), }, }, }) ``` ### 3. Write tests Create a `test/` directory and add `.test.ts` files: ```typescript theme={null} import { createMockActionContext } from '@activepieces/pieces-framework'; import { myAction } from '../src/lib/actions/my-action'; describe('myAction', () => { test('does something', async () => { const ctx = createMockActionContext({ propsValue: { inputField: 'test value', }, }); const result = await myAction.run(ctx); expect(result).toBe('expected output'); }); }); ``` ### 4. Run tests ```bash theme={null} # Run tests for a specific piece npx turbo test --filter=@activepieces/piece-text-helper # Run tests directly from the piece directory cd packages/pieces/core/text-helper npx vitest run ``` # Piece Auth Source: https://www.activepieces.com/docs/build-pieces/piece-reference/authentication Learn about piece authentication Piece authentication is used to gather user credentials and securely store them for future use in different flows. The authentication must be defined as the `auth` parameter in the `createPiece`, `createTrigger`, and `createAction` functions. This requirement ensures that the type of authentication can be inferred correctly in triggers and actions. The auth parameter for `createPiece`, `createTrigger`, and `createAction` functions can take an array, but you cannot have more than one auth property of the same type, i.e two OAUTH2 properties. ### Secret Text This authentication collects sensitive information, such as passwords or API keys. It is displayed as a masked input field. **Example:** ```typescript theme={null} PieceAuth.SecretText({ displayName: 'API Key', description: 'Enter your API key', required: true, // Optional Validation validate: async ({auth}) => { if(auth.startsWith('sk_')){ return { valid: true, } } return { valid: false, error: 'Invalid Api Key' } } }) ``` ### Username and Password This authentication collects a username and password as separate fields. **Example:** ```typescript theme={null} PieceAuth.BasicAuth({ displayName: 'Credentials', description: 'Enter your username and password', required: true, username: { displayName: 'Username', description: 'Enter your username', }, password: { displayName: 'Password', description: 'Enter your password', }, // Optional Validation validate: async ({auth}) => { if(auth){ return { valid: true, } } return { valid: false, error: 'Invalid Api Key' } } }) ``` ### Custom This authentication allows for custom authentication by collecting specific properties, such as a base URL and access token. **Example:** ```typescript theme={null} PieceAuth.CustomAuth({ displayName: 'Custom Authentication', description: 'Enter custom authentication details', props: { base_url: Property.ShortText({ displayName: 'Base URL', description: 'Enter the base URL', required: true, }), access_token: PieceAuth.SecretText({ displayName: 'Access Token', description: 'Enter the access token', required: true }) }, // Optional Validation validate: async ({auth}) => { if(auth){ return { valid: true, } } return { valid: false, error: 'Invalid Api Key' } }, required: true }) ``` ### OAuth2 This authentication collects OAuth2 authentication details, including the authentication URL, token URL, and scope. **Example:** ```typescript theme={null} PieceAuth.OAuth2({ displayName: 'OAuth2 Authentication', grantType: OAuth2GrantType.AUTHORIZATION_CODE, required: true, authUrl: 'https://example.com/auth', tokenUrl: 'https://example.com/token', scope: ['read', 'write'] }) ``` Please note `OAuth2GrantType.CLIENT_CREDENTIALS` is also supported for service-based authentication. # Enable Custom API Calls Source: https://www.activepieces.com/docs/build-pieces/piece-reference/custom-api-calls Learn how to enable custom API calls for your pieces Custom API Calls allow the user to send a request to a specific endpoint if no action has been implemented for it. This will show in the actions list of the piece as `Custom API Call`, to enable this action for a piece, you need to call the `createCustomApiCallAction` in your actions array. ## Basic Example The example below implements the action for the OpenAI piece. The OpenAI piece uses a `Bearer token` authorization header to identify the user sending the request. ```typescript theme={null} actions: [ ...yourActions, createCustomApiCallAction({ // The auth object defined in the piece auth: openaiAuth, // The base URL for the API baseUrl: () => { 'https://api.openai.com/v1' }, // Mapping the auth object to the needed authorization headers authMapping: async (auth) => { return { 'Authorization': `Bearer ${auth}` } } }) ] ``` ## Dynamic Base URL and Basic Auth Example The example below implements the action for the Jira Cloud piece. The Jira Cloud piece uses a dynamic base URL for it's actions, where the base URL changes based on the values the user authenticated with. We will also implement a Basic authentication header. ```typescript theme={null} actions: [ ...yourActions, createCustomApiCallAction({ baseUrl: (auth) => { return `${(auth as JiraAuth).instanceUrl}/rest/api/3` }, auth: jiraCloudAuth, authMapping: async (auth) => { const typedAuth = auth as JiraAuth return { 'Authorization': `Basic ${typedAuth.email}:${typedAuth.apiToken}` } } }) ] ``` # Piece Examples Source: https://www.activepieces.com/docs/build-pieces/piece-reference/examples Explore a collection of example triggers and actions To get the full benefit, it is recommended to read the tutorial first. ## Triggers: **Webhooks:** * [New Form Submission on Typeform](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/typeform/src/lib/trigger/new-submission.ts) **Polling:** * [New Completed Task On Todoist](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/todoist/src/lib/triggers/task-completed-trigger.ts) ## Actions: * [Send a message On Discord](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/discord/src/lib/actions/send-message-webhook.ts) * [Send an mail On Gmail](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/gmail/src/lib/actions/send-email-action.ts) ## Authentication **OAuth2:** * [Slack](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/slack/src/index.ts) * [Gmail](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/gmail/src/index.ts) **API Key:** * [Sendgrid](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/sendgrid/src/index.ts) **Basic Authentication:** * [Twilio](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/twilio/src/index.ts) # External Libraries Source: https://www.activepieces.com/docs/build-pieces/piece-reference/external-libraries Learn how to install and use external libraries. The Activepieces repository is structured as a monorepo, employing Nx as its build tool. To keep our main `package.json` as light as possible, we keep libraries that are only used for a piece in the piece `package.json` . This means when adding a new library you should navigate to the piece folder and install the library with our package manager `bun` ```bash theme={null} cd packages/pieces/ bun install --save ``` * Import the library into your piece. Guidelines: * Make sure you are using well-maintained libraries. * Ensure that the library size is not too large to avoid bloating the bundle size; this will make the piece load faster in the sandbox. # Files Source: https://www.activepieces.com/docs/build-pieces/piece-reference/files Learn how to use files object to create file references. The `ctx.files` object allow you to store files in local storage or in a remote storage depending on the run environment. ## Write You can use the `write` method to write a file to the storage, It returns a string that can be used in other actions or triggers properties to reference the file. **Example:** ```ts theme={null} const fileReference = await files.write({ fileName: 'file.txt', data: Buffer.from('text') }); ``` This code will store the file in the database If the run environment is testing mode since it will be required to test other steps, other wise it will store it in the local temporary directory. For Reading the file If you are using the file property in a trigger or action, It will be automatically parsed and you can use it directly, please refer to `Property.File` in the [properties](./properties#file) section. # Flow Control Source: https://www.activepieces.com/docs/build-pieces/piece-reference/flow-control Learn How to Control Flow from Inside the Piece Flow Controls provide the ability to control the flow of execution from inside a piece. By using the `ctx` parameter in the `run` method of actions, you can perform various operations to control the flow. ## Stop Flow You can stop the flow and provide a response to the webhook trigger. This can be useful when you want to terminate the execution of the piece and send a specific response back. **Example with Response:** ```typescript theme={null} context.run.stop({ response: { status: context.propsValue.status ?? StatusCodes.OK, body: context.propsValue.body, headers: (context.propsValue.headers as Record) ?? {}, }, }); ``` **Example without Response:** ```typescript theme={null} context.run.stop(); ``` ## Pause Flow and Wait for Webhook You can pause flow and return HTTP response, also provide a callback to URL that you can call with certain payload and continue the flow. **Example:** ```typescript theme={null} ctx.run.pause({ pauseMetadata: { type: PauseType.WEBHOOK, response: { callbackUrl: context.generateResumeUrl({ queryParams: {}, }), }, }, }); ``` ## Pause Flow and Delay You can pause or delay the flow until a specific timestamp. Currently, the only supported type of pause is a delay based on a future timestamp. **Example:** ```typescript theme={null} ctx.run.pause({ pauseMetadata: { type: PauseType.DELAY, resumeDateTime: futureTime.toUTCString() } }); ``` These flow hooks give you control over the execution of the piece by allowing you to stop the flow or pause it until a certain condition is met. You can use these hooks to customize the behavior and flow of your actions. # Piece i18n Source: https://www.activepieces.com/docs/build-pieces/piece-reference/i18n Learn about translating pieces to multiple locales Run the following command to create a translation file with all the strings that need translation in your piece ```bash theme={null} npm run cli pieces generate-translation-file PIECE_FOLDER_NAME ``` Make a copy of `packages/pieces///src/i18n/translation.json`, name it `.json` i.e fr.json and translate the values. For open source pieces, you can use the [Crowdin project](https://crowdin.com/project/activepieces) to translate to different languages. These translations will automatically sync back to your code. After following the steps to [setup your development environment](/build-pieces/building-pieces/development-setup), click the small cog icon next to the logo in your dashboard and change the locale. Locales
In the builder your piece will now appear in the translated language: French Webhooks
Follow the docs here to [publish your piece](/build-pieces/sharing-pieces/overview)
# Persistent Storage Source: https://www.activepieces.com/docs/build-pieces/piece-reference/persistent-storage Learn how to store and retrieve data from a key-value store The `ctx` parameter inside triggers and actions provides a simple key/value storage mechanism. The storage is persistent, meaning that the stored values are retained even after the execution of the piece. By default, the storage operates at the flow level, but it can also be configured to store values at the project level. The storage scope is completely isolated. If a key is stored in a different scope, it will not be fetched when requested in different scope. ## Put You can store a value with a specified key in the storage. **Example:** ```typescript theme={null} ctx.store.put('KEY', 'VALUE', StoreScope.PROJECT); ``` ## Get You can retrieve the value associated with a specific key from the storage. **Example:** ```typescript theme={null} const value = ctx.store.get('KEY', StoreScope.PROJECT); ``` ## Delete You can delete a key-value pair from the storage. **Example:** ```typescript theme={null} ctx.store.delete('KEY', StoreScope.PROJECT); ``` These storage operations allow you to store, retrieve, and delete key-value pairs in the persistent storage. You can use this storage mechanism to store and retrieve data as needed within your triggers and actions. # Piece Versioning Source: https://www.activepieces.com/docs/build-pieces/piece-reference/piece-versioning Learn how to version your pieces Pieces are npm packages and follows **semantic versioning**. ## Semantic Versioning The version number consists of three numbers: `MAJOR.MINOR.PATCH`, where: * **MAJOR** It should be incremented when there are breaking changes to the piece. * **MINOR** It should be incremented for new features or functionality that is compatible with the previous version, unless the major version is less than 1.0, in which case it can be a breaking change. * **PATCH** It should be incremented for bug fixes and small changes that do not introduce new features or break backward compatibility. ## Engine The engine will use the most up-to-date compatible version for a given piece version during the **DRAFT** flow versions. Once the flow is published, all pieces will be locked to a specific version. **Case 1: Piece Version is Less Than 1.0**: The engine will select the latest **patch** version that shares the same **minor** version number. **Case 2: Piece Version Reaches Version 1.0**: The engine will select the latest **minor** version that shares the same **major** version number. ## Examples when you make a change, remember to increment the version accordingly. ### Breaking changes * Remove an existing action. * Add a required `action` prop. * Remove an existing action prop, whether required or optional. * Remove an attribute from an action output. * Change the existing behavior of an action/trigger. ### Non-breaking changes * Add a new action. * Add an optional `action` prop. * Add an attribute to an action output. i.e., any removal is breaking, any required addition is breaking, everything else is not breaking. # Props Source: https://www.activepieces.com/docs/build-pieces/piece-reference/properties Learn about different types of properties used in triggers / actions Properties are used in actions and triggers to collect information from the user. They are also displayed to the user for input. Here are some commonly used properties: ## Basic Properties These properties collect basic information from the user. ### Short Text This property collects a short text input from the user. **Example:** ```typescript theme={null} Property.ShortText({ displayName: 'Name', description: 'Enter your name', required: true, defaultValue: 'John Doe', }); ``` ### Long Text This property collects a long text input from the user. **Example:** ```typescript theme={null} Property.LongText({ displayName: 'Description', description: 'Enter a description', required: false, }); ``` ### Checkbox This property presents a checkbox for the user to select or deselect. **Example:** ```typescript theme={null} Property.Checkbox({ displayName: 'Agree to Terms', description: 'Check this box to agree to the terms', required: true, defaultValue: false, }); ``` ### Markdown This property displays a markdown snippet to the user, useful for documentation or instructions. It includes a `variant` option to style the markdown, using the `MarkdownVariant` enum: * **BORDERLESS**: For a minimalistic, no-border layout. * **INFO**: Displays informational messages. * **WARNING**: Alerts the user to cautionary information. * **TIP**: Highlights helpful tips or suggestions. The default value for `variant` is **INFO**. **Example:** ```typescript theme={null} Property.MarkDown({ value: '## This is a markdown snippet', variant: MarkdownVariant.WARNING, }), ``` If you want to show a webhook url to the user, use `{{ webhookUrl }}` in the markdown snippet. ### DateTime This property collects a date and time from the user. **Example:** ```typescript theme={null} Property.DateTime({ displayName: 'Date and Time', description: 'Select a date and time', required: true, defaultValue: '2023-06-09T12:00:00Z', }); ``` ### Number This property collects a numeric input from the user. **Example:** ```typescript theme={null} Property.Number({ displayName: 'Quantity', description: 'Enter a number', required: true, }); ``` ### Static Dropdown This property presents a dropdown menu with predefined options. **Example:** ```typescript theme={null} Property.StaticDropdown({ displayName: 'Country', description: 'Select your country', required: true, options: { options: [ { label: 'Option One', value: '1', }, { label: 'Option Two', value: '2', }, ], }, }); ``` ### Static Multiple Dropdown This property presents a dropdown menu with multiple selection options. **Example:** ```typescript theme={null} Property.StaticMultiSelectDropdown({ displayName: 'Colors', description: 'Select one or more colors', required: true, options: { options: [ { label: 'Red', value: 'red', }, { label: 'Green', value: 'green', }, { label: 'Blue', value: 'blue', }, ], }, }); ``` ### JSON This property collects JSON data from the user. **Example:** ```typescript theme={null} Property.Json({ displayName: 'Data', description: 'Enter JSON data', required: true, defaultValue: { key: 'value' }, }); ``` ### Dictionary This property collects key-value pairs from the user. **Example:** ```typescript theme={null} Property.Object({ displayName: 'Options', description: 'Enter key-value pairs', required: true, defaultValue: { key1: 'value1', key2: 'value2', }, }); ``` ### File This property collects a file from the user, either by providing a URL or uploading a file. **Example:** ```typescript theme={null} Property.File({ displayName: 'File', description: 'Upload a file', required: true, }); ``` ### Array of Strings This property collects an array of strings from the user. **Example:** ```typescript theme={null} Property.Array({ displayName: 'Tags', description: 'Enter tags', required: false, defaultValue: ['tag1', 'tag2'], }); ``` ### Array of Fields This property collects an array of objects from the user. **Example:** ```typescript theme={null} Property.Array({ displayName: 'Fields', description: 'Enter fields', properties: { fieldName: Property.ShortText({ displayName: 'Field Name', required: true, }), fieldType: Property.StaticDropdown({ displayName: 'Field Type', required: true, options: { options: [ { label: 'TEXT', value: 'TEXT' }, { label: 'NUMBER', value: 'NUMBER' }, ], }, }), }, required: false, defaultValue: [], }); ``` ## Dynamic Data Properties These properties provide more advanced options for collecting user input. ### Dropdown This property allows for dynamically loaded options based on the user's input. **Example:** ```typescript theme={null} Property.Dropdown({ displayName: 'Options', description: 'Select an option', required: true, auth: yourPieceAuth, refreshers: ['auth'], refreshOnSearch: false, options: async ({ auth }, { searchValue }) => { // Search value only works when refreshOnSearch is true if (!auth) { return { disabled: true, }; } return { options: [ { label: 'Option One', value: '1', }, { label: 'Option Two', value: '2', }, ], }; }, }); ``` When accessing the Piece auth, be sure to use exactly `auth` as it is hardcoded. However, for other properties, use their respective names. ### Multi-Select Dropdown This property allows for multiple selections from dynamically loaded options. **Example:** ```typescript theme={null} Property.MultiSelectDropdown({ displayName: 'Options', description: 'Select one or more options', required: true, refreshers: ['auth'], auth: yourPieceAuth, options: async ({ auth }) => { if (!auth) { return { disabled: true, }; } return { options: [ { label: 'Option One', value: '1', }, { label: 'Option Two', value: '2', }, ], }; }, }); ``` When accessing the Piece auth, be sure to use exactly `auth` as it is hardcoded. However, for other properties, use their respective names. ### Dynamic Properties This property is used to construct forms dynamically based on API responses or user input. **Example:** ```typescript theme={null} import { httpClient, HttpMethod, } from '@activepieces/pieces-common'; Property.DynamicProperties({ description: 'Dynamic Form', displayName: 'Dynamic Form', required: true, refreshers: ['auth'], auth: yourPieceAuth, props: async ({auth}) => { const apiEndpoint = 'https://someapi.com'; const response = await httpClient.sendRequest<{ values: [string[]][] }>({ method: HttpMethod.GET, url: apiEndpoint , //you can add the auth value to the headers }); const properties = { prop1: Property.ShortText({ displayName: 'Property 1', description: 'Enter property 1', required: true, }), prop2: Property.Number({ displayName: 'Property 2', description: 'Enter property 2', required: false, }), }; return properties; }, }); ``` ### Custom Property (BETA) This feature is still in BETA and not fully released yet, please let us know if you use it and face any issues and consider it a possibility could have breaking changes in the future This is a property that lets you inject JS code into the frontend and manipulate the DOM of this content however you like, it is extremely useful in case you are [embedding](/embedding/overview) Activepieces and want to have a way to communicate with the SaaS embedding it. It has a `code` property which is a function that takes in an object parameter which will have the following schema: | Parameter Name | Type | Description | | -------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | onChange | `(value:unknown)=>void` | A callback you call to set the value of your input (only call this inside event handlers) | | value | `unknown` | Whatever the type of the value you pass to onChange | | containerId | `string` | The ID of an HTML element in which you can modify the DOM however you like | | isEmbedded | `boolean` | The flag that tells you if the code is running inside an [embedded instance](/embedding/overview) of Activepieces | | projectId | `string` | The project ID of the flow the step that contains this property is in | | disabled | `boolean` | The flag that tells you whether or not the property is disabled | | property | `{ displayName:string, description?: string, required: boolean}` | The current property information | * You can return a clean up function at the end of the `code` property function to remove any listeners or HTML elements you inserted (this is important for development mode, the component gets [mounted twice](https://react.dev/reference/react/useEffect#my-effect-runs-twice-when-the-component-mounts)). * This function must be pure without any imports from external packages or variables outside the function scope. * **Must** mark your piece `minimumSupportedRelease` property to be at least `0.58.0` after introducing this property to it. Here is how to define such a property: ```typescript theme={null} Property.Custom({ code:(({value,onChange,containerId})=>{ const container = document.getElementById(containerId); const input = document.createElement('input'); input.classList.add(...['border','border-solid', 'border-border', 'rounded-md']) input.type = 'text'; input.value = `${value}`; input.oninput = (e: Event) => { const value = (e.target as HTMLInputElement).value; onChange(value); } container!.appendChild(input); const windowCallback = (e:MessageEvent<{type:string,value:string,propertyName:string}>) => { if(e.data.type === 'updateInput' && e.data.propertyName === 'YOUR_PROPERTY_NAME'){ input.value= e.data.value; onChange(e.data.value); } } window.addEventListener('message', windowCallback); return ()=>{ window.removeEventListener('message', windowCallback); container!.removeChild(input); } }), displayName: 'Custom Property', required: true }) ``` * If you would like to know more about how to setup communication between Activepieces and the SaaS that's embedding it, check the [window postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). # Props Validation Source: https://www.activepieces.com/docs/build-pieces/piece-reference/properties-validation Learn about different types of properties validation Activepieces uses Zod for runtime validation of piece properties. Zod provides a powerful schema validation system that helps ensure your piece receives valid inputs. To use Zod validation in your piece, first import the validation helper and Zod: Please make sure the `minimumSupportedRelease` is set to at least `0.36.1` for the validation to work. ```typescript theme={null} import { createAction, Property } from '@activepieces/pieces-framework'; import { propsValidation } from '@activepieces/pieces-common'; import { z } from 'zod'; export const getIcecreamFlavor = createAction({ name: 'get_icecream_flavor', // Unique name for the action. displayName: 'Get Ice Cream Flavor', description: 'Fetches a random ice cream flavor based on user preferences.', props: { sweetnessLevel: Property.Number({ displayName: 'Sweetness Level', required: true, description: 'Specify the sweetness level (0 to 10).', }), includeToppings: Property.Checkbox({ displayName: 'Include Toppings', required: false, description: 'Should the flavor include toppings?', defaultValue: true, }), numberOfFlavors: Property.Number({ displayName: 'Number of Flavors', required: true, description: 'How many flavors do you want to fetch? (1-5)', defaultValue: 1, }), }, async run({ propsValue }) { // Validate the input properties using Zod await propsValidation.validateZod(propsValue, { sweetnessLevel: z.number().min(0).max(10, 'Sweetness level must be between 0 and 10.'), numberOfFlavors: z.number().min(1).max(5, 'You can fetch between 1 and 5 flavors.'), }); // Action logic const sweetnessLevel = propsValue.sweetnessLevel; const includeToppings = propsValue.includeToppings ?? true; // Default to true const numberOfFlavors = propsValue.numberOfFlavors; // Simulate fetching random ice cream flavors const allFlavors = [ 'Vanilla', 'Chocolate', 'Strawberry', 'Mint', 'Cookie Dough', 'Pistachio', 'Mango', 'Coffee', 'Salted Caramel', 'Blackberry', ]; const selectedFlavors = allFlavors.slice(0, numberOfFlavors); return { message: `Here are your ${numberOfFlavors} flavors: ${selectedFlavors.join(', ')}`, sweetnessLevel: sweetnessLevel, includeToppings: includeToppings, }; }, }); ``` # Overview Source: https://www.activepieces.com/docs/build-pieces/piece-reference/triggers/overview This tutorial explains three techniques for creating triggers: * `Polling`: Periodically call endpoints to check for changes. * `Webhooks`: Listen to user events through a single URL. * `App Webhooks (Subscriptions)`: Use a developer app (using OAuth2) to receive all authorized user events at a single URL (Not Supported). to create new trigger run following command, ```bash theme={null} npm run cli triggers create ``` 1. `Piece Folder Name`: This is the name associated with the folder where the trigger resides. It helps organize and categorize triggers within the piece. 2. `Trigger Display Name`: The name users see in the interface, conveying the trigger's purpose clearly. 3. `Trigger Description`: A brief, informative text in the UI, guiding users about the trigger's function and purpose. 4. `Trigger Technique`: Specifies the trigger type - either polling or webhook. # Trigger Structure ```typescript theme={null} export const createNewIssue = createTrigger({ auth: PieceAuth | undefined name: string, // Unique name across the piece. displayName: string, // Display name on the interface. description: string, // Description for the action sampleData: null, type: TriggerStrategy.WEBHOOK | TriggerStrategy.POLLING | TriggerStrategy.APP_WEBHOOK, props: {}; // Required properties from the user. // Run when the user enable or publish the flow. onEnable: (ctx) => {}, // Run when the user disable the flow or // the old flow is deleted after new one is published. onDisable: (ctx) => {}, // Trigger implementation, It takes context as parameter. // should returns an array of payload, each payload considered run: async run(ctx): unknown[] => {} }) ``` It's important to note that the `run` method returns an array. The reason for this is that a single polling can contain multiple triggers, so each item in the array will trigger the flow to run. ## Context Object The Context object contains multiple helpful pieces of information and tools that can be useful while developing. ```typescript theme={null} // Store: A simple, lightweight key-value store that is helpful when you are developing triggers that persist between runs, used to store information like the last polling date. await context.store.put('_lastFetchedDate', new Date()); const lastFetchedData = await context.store.get('_lastFetchedDate', new Date()); // Webhook URL: A unique, auto-generated URL that will trigger the flow. Useful when you need to develop a trigger based on webhooks. context.webhookUrl; // Payload: Contains information about the HTTP request sent by the third party. It has three properties: status, headers, and body. context.payload; // PropsValue: Contains the information filled by the user in defined properties. context.propsValue; ``` **App Webhooks (Not Supported)** Certain services, such as `Slack` and `Square`, only support webhooks at the developer app level. This means that all authorized users for the app will be sent to the same endpoint. While this technique will be supported soon, for now, a workaround is to perform polling on the endpoint. # Polling Trigger Source: https://www.activepieces.com/docs/build-pieces/piece-reference/triggers/polling-trigger Periodically call endpoints to check for changes The way polling triggers usually work is as follows: **On Enable:** Store the last timestamp or most recent item id using the context store property. **Run:** This method runs every **5 minutes**, fetches the endpoint between a certain timestamp or traverses until it finds the last item id, and returns the new items as an array. **Testing:** You can implement a test function which should return some of the most recent items. It's recommended to limit this to five. **Examples:** * [New Record Airtable](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/airtable/src/lib/trigger/new-record.trigger.ts) * [New Updated Item Salesforce](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/salesforce/src/lib/trigger/new-updated-record.ts) # Polling library There multiple strategy to implement polling triggers, and we have created a library to help you with that. ## Strategies **Timebased:** This strategy fetches new items using a timestamp. You need to implement the items method, which should return the most recent items. The library will detect new items based on the timestamp. The polling object's generic type consists of the props value and the object type. ```typescript theme={null} const polling: Polling> = { strategy: DedupeStrategy.TIMEBASED, items: async ({ propsValue, lastFetchEpochMS }) => { // Todo implement the logic to fetch the items const items = [ {id: 1, created_date: '2021-01-01T00:00:00Z'}, {id: 2, created_date: '2021-01-01T00:00:00Z'}]; return items.map((item) => ({ epochMilliSeconds: dayjs(item.created_date).valueOf(), data: item, })); } } ``` **Last ID Strategy:** This strategy fetches new items based on the last item ID. To use this strategy, you need to implement the items method, which should return the most recent items. The library will detect new items after the last item ID. The polling object's generic type consists of the props value and the object type ```typescript theme={null} const polling: Polling, Record> = { strategy: DedupeStrategy.LAST_ITEM, items: async ({ propsValue }) => { // Implement the logic to fetch the items const items = [{ id: 1 }, { id: 2 }]; return items.map((item) => ({ id: item.id, data: item, })); } } ``` ## Trigger Implementation After implementing the polling object, you can use the polling helper to implement the trigger. ```typescript theme={null} export const newTicketInView = createTrigger({ name: 'new_ticket_in_view', displayName: 'New ticket in view', description: 'Triggers when a new ticket is created in a view', type: TriggerStrategy.POLLING, props: { authentication: Property.SecretText({ displayName: 'Authentication', description: markdownProperty, required: true, }), }, sampleData: {}, onEnable: async (context) => { await pollingHelper.onEnable(polling, { store: context.store, propsValue: context.propsValue, auth: context.auth }) }, onDisable: async (context) => { await pollingHelper.onDisable(polling, { store: context.store, propsValue: context.propsValue, auth: context.auth }) }, run: async (context) => { return await pollingHelper.poll(polling, context); }, test: async (context) => { return await pollingHelper.test(polling, context); } }); ``` # Webhook Trigger Source: https://www.activepieces.com/docs/build-pieces/piece-reference/triggers/webhook-trigger Listen to user events through a single URL The way webhook triggers usually work is as follows: **On Enable:** Use `context.webhookUrl` to perform an HTTP request to register the webhook in a third-party app, and store the webhook Id in the `store`. **On Handshake:** Some services require a successful handshake request usually consisting of some challenge. It works similar to a normal run except that you return the correct challenge response. This is optional and in order to enable the handshake you need to configure one of the available handshake strategies in the `handshakeConfiguration` option. **Run:** You can find the HTTP body inside `context.payload.body`. If needed, alter the body; otherwise, return an array with a single item `context.payload.body`. **Disable:** Using the `context.store`, fetch the webhook ID from the enable step and delete the webhook on the third-party app. **Testing:** You cannot test it with Test Flow, as it uses static sample data provided in the piece. To test the trigger, publish the flow, perform the event. Then check the flow runs from the main dashboard. **Examples:** * [New Form Submission on Typeform](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/typeform/src/lib/trigger/new-submission.ts) To make your webhook accessible from the internet, you need to expose your local development instance to the internet, do the following: 1. Install [localxpose](https://localxpose.io/docs#start-your-first-tunnel). 2. Follow the documentation to start your first tunnel to localhost:4200. 3. Copy the tunnel domain, i.e wozcsvaint.loclx.io, and replace the `AP_FRONTEND_URL` environment variable in `packages/server/api/.env` with the exposed url, i.e [https://wozcsvaint.loclx.io](https://wozcsvaint.loclx.io) 4. Go to /packages/web/vite.config.ts, uncomment allowedHosts and replace the value with the same tunnel domain, i.e wozcsvaint.loclx.io. Once you have completed these configurations, you will be able to test webhook triggers and run published flows that have them. # Community (Public NPM) Source: https://www.activepieces.com/docs/build-pieces/sharing-pieces/community Learn how to publish your piece to the community. You can publish your pieces to the npm registry and share them with the community. Users can install your piece from Settings -> My Pieces -> Install Piece -> type in the name of your piece package. Make sure you are logged in to npm. If not, please run: ```bash theme={null} npm login ``` Rename the piece name in `package.json` to something unique or related to your organization's scope (e.g., `@my-org/piece-PIECE_NAME`). You can find it at `packages/pieces/PIECE_NAME/package.json`. Don't forget to increase the version number in `package.json` for each new release. Replace `PIECE_FOLDER_NAME` with the name of the folder. Run the following command: ```bash theme={null} npm run publish-piece PIECE_FOLDER_NAME ``` **Congratulations! You can now import the piece from the settings page.** # Contribute Source: https://www.activepieces.com/docs/build-pieces/sharing-pieces/contribute Learn how to contribute a piece to the main repository. * Build and test your piece. * Open a pull request from your repository to the main fork. * A maintainer will review your work closely. * Once the pull request is approved, it will be merged into the main branch. * Your piece will be available within a few minutes. * An automatic GitHub action will package it and create an npm package on npmjs.com. # Overview Source: https://www.activepieces.com/docs/build-pieces/sharing-pieces/overview Learn the different ways to publish your own piece on activepieces. ## Methods * [Contribute Back](/build-pieces/sharing-pieces/contribute): Publish your piece by contributing back your piece to main repository. * [Community](/build-pieces/sharing-pieces/community): Publish your piece on npm directly and share it with the community. * [Private](/build-pieces/sharing-pieces/private): Publish your piece on activepieces privately. # Private Source: https://www.activepieces.com/docs/build-pieces/sharing-pieces/private Learn how to share your pieces privately. This guide assumes you have already created a piece and created a private fork of our repository, and you would like to package it as a file and upload it. Friendly Tip: There is a CLI to easily upload it to your platform. Please check out [Publish Custom Pieces](../misc/publish-piece). Build the piece using the following command. Make sure to replace `${name}` with your piece name. ```bash theme={null} npm run pieces -- build --name=${name} ``` More information about building pieces can be found [here](../misc/build-piece). Upload the generated tarball inside `dist/packages/pieces/${name}`from Activepieces Platform Admin -> Pieces Manage Pieces # Show/Hide Pieces Source: https://www.activepieces.com/docs/embedding/customize-pieces If you would like to only show specific pieces to your embedding users, we recommend you do the following: Tag the pieces you would like to show to your user by going to **Platform Admin -> Setup -> Pieces**, selecting the pieces you would like to tag and hit **Apply Tags** Bulk Tag You need to specify the tags of pieces in the token, check how to generate token in [provisioning users](./provision-users). You should specify the `pieces` claim like this: ```json theme={null} { /// Other claims "piecesFilterType": "ALLOWED", "piecesTags": [ "free" ] } ``` Each time the token is used by the embedding SDK, it will sync all pieces with these tags to the token's project. The project will only contain the pieces that contain these tags. # Embed Builder Source: https://www.activepieces.com/docs/embedding/embed-builder This documentation explains how to embed the Activepieces iframe inside your application and customize it. ## Configure SDK Adding the embedding SDK script will initialize an object in your window called `activepieces`, which has a method called `configure` that you should call after the container has been rendered. The following scripts shouldn't contain the `async` or `defer` attributes. These steps assume you have already generated a JWT token from the backend. If not, please check the [provision-users](./provision-users) page. ```html theme={null} ``` `configure` returns a promise which is resolved after authentication is done. Please check the [navigation](./navigation) section, as it's very important to understand how navigation works and how to supply an auto-sync experience. **Configure Parameters:** | Parameter Name | Required | Type | Description | | ------------------------------------------ | -------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | instanceUrl | ✅ | string | The url of the instance hosting Activepieces, could be [https://cloud.activepieces.com](https://cloud.activepieces.com) if you are a cloud user. | | jwtToken | ✅ | string | The jwt token you generated to authenticate your users to Activepieces. | | prefix | ❌ | string | Some customers have an embedding prefix, like this `/`. For example if the prefix is `/automation` and the Activepieces url is `/flows` the full url would be `/automation/flows`. | | embedding.containerId | ❌ | string | The html element's id that is going to be containing Activepieces's iframe. | | embedding.builder.disableNavigation | ❌ | boolean \| `keep_home_button_only` | Hides the folder name, home button (if not set to [`keep_home_button_only`](./sdk-changelog#20%2F05%2F2025-0-4-0)) and delete option in the builder, by default it is false. | | embedding.builder.hideFlowName | ❌ | boolean | Hides the flow name and flow actions dropdown in the builder's header, by default it is false. | | embedding.builder.homeButtonClickedHandler | ❌ | `()=>void` | Callback that stops home button from navigating to dashboard and overrides it with this handler (added in [0.4.0](./sdk-changelog#20%2F05%2F2025-0-4-0)) | | embedding.builder.homeButtonIcon | ❌ | `logo` \| `back` | if set to **`back`** the tooltip shown on hovering the home button is removed (added in [0.5.0](./sdk-changelog#03%2F07%2F2025-0-5-0)) | | embedding.dashboard.hideSidebar | ❌ | boolean | Controls the visibility of the sidebar in the dashboard, by default it is false. | | embedding.dashboard.hideFlowsPageNavbar | ❌ | boolean | Controls the visibility of the navbar showing flows,issues and runs above the flows table in the dashboard, by default it is false. (added in [0.6.0](./sdk-changelog#07%2F07%2F2025-0-6-0)) | | embedding.dashboard.hidePageHeader | ❌ | boolean | Hides the page header in the dashboard by default it is false. (added in [0.8.0](./sdk-changelog#09%2F21%2F2025-0-8-0)) | | embedding.hideFolders | ❌ | boolean | Hides all things related to folders in both the flows table and builder by default it is false. | | embedding.styling.fontUrl | ❌ | string | The url of the font to be used in the embedding, by default it is `https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap`. | | embedding.styling.fontFamily | ❌ | string | The font family to be used in the embedding, by default it is `Roboto`. | | embedding.styling.mode | ❌ | `light` \| `dark` | Controls light/dark mode (added in [0.5.0](./sdk-changelog#03%2F07%2F2025-0-5-0)) | | embedding.hideExportAndImportFlow | ❌ | boolean | Hides the option to export or import flows (added in [0.4.0](./sdk-changelog#20%2F05%2F2025-0-4-0)) | | embedding.hideDuplicateFlow | ❌ | boolean | Hides the option to duplicate a flow (added in [0.5.0](./sdk-changelog#03%2F07%2F2025-0-5-0)) | | embedding.locale | ❌ | `en` \| `nl` \| `de` \| `fr` \| `es` \| `ja` \| `zh` \| `pt` \| `zh-TW` \| `ru` \| | it takes [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) locale codes (added in [0.5.0](./sdk-changelog#03%2F07%2F2025-0-5-0)) | | navigation.handler | ❌ | `({route:string}) => void` | This callback will be triggered each time a route in Activepieces changes, you can read more about it [here](/embedding/navigation) | For the font to be loaded, you need to set both the `fontUrl` and `fontFamily` properties. If you only set one of them, the default font will be used. The default font is `Roboto`. The font weights we use are the default font-weights from [tailwind](https://tailwindcss.com/docs/font-weight). # Create/Update Connections Source: https://www.activepieces.com/docs/embedding/embed-connections **Requirements:** * Activepieces version 0.34.5 or higher * SDK version 0.3.2 or higher "connectionName" is the externalId of the connection (you can get it by hovering the connection name in the connections table).
We kept the same parameter name for backward compatibility, anyone upgrading their instance from \< 0.35.1, will not face issues in that regard.
**Breaking Change:**

If your Activepieces instance version is \< 0.45.0 and (you are using the connect method from the embed sdk, and need the connection externalId to be returned after the user creates it OR if you want to reconnect a specific connection with an externalId), you must upgrade your instance to >= 0.45.0
* You can use the embedded SDK in your SaaS to allow your users to create connections and store them in Activepieces. Follow the instructions in the [Embed Builder](./embed-builder). After initializing the SDK, you will have access to a property called `activepieces` inside your `window` object. Call its `connect` method to open a new connection dialog as follows. ```html theme={null} ``` **Connect Parameters:** | Parameter Name | Required | Type | Description | | -------------- | -------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | pieceName | ✅ | string | The name of the piece you want to create a connection for. | | connectionName | ❌ | string | The external Id of the connection (you can get it by hovering the connection name in the connections table), when provided the connection created/upserted will use this as the external Id and display name. | | newWindow | ❌ | \{ width?: number, height?: number, top?: number, left?: number } | If set the connection dialog will be opened in a new window instead of an iframe taking the full page. | **Connect Result** The `connect` method returns a `promise` that resolves to the following: ```ts theme={null} { connection?: { id: string, name: string } } ``` `name` is the externalId of the connection. `connection` is undefined if the user closes the dialog and doesn't create a connection. You can use the `connections` piece in the builder to retrieve the created connection using its name. Connections in Builder Connections in Builder # Navigation Source: https://www.activepieces.com/docs/embedding/navigation By default, navigating within your embedded instance of Activepieces doesn't affect the client's browser history or viewed URL. Activepieces only provide a **handler**, that trigger on every route change in the **iframe**. ## Automatically Sync URL You can use the following snippet when configuring the SDK, which will implement a handler that syncs the Activepieces iframe with your browser: The following snippet listens when the user clicks backward, so it syncs the route back to the iframe using `activepieces.navigate` and in the handler, it updates the URL of the browser. ```js theme={null} const instanceUrl = 'YOUR_INSTANCE_URL'; const jwtToken = 'YOUR_GENERATED_JWT_TOKEN'; const containerId = 'YOUR_CONTAINER_ID'; activepieces.configure({ instanceUrl, jwtToken, embedding: { containerId, builder: { disableNavigation: false, hideFlowName: false }, dashboard: { hideSidebar: false }, hideFolders: false, navigation: { handler: ({ route }) => { //route can include search params at the end of it if (!window.location.href.endsWith(route)) { window.history.pushState({}, "", window.location.origin + route); } } } }, }); window.addEventListener("popstate", () => { const route = activepieces.extractActivepiecesRouteFromUrl({ vendorUrl: window.location.href }); activepieces.navigate({ route }); }); ``` ## Navigate Method If you use `activepieces.navigate({ route: '/flows' })` this will tell the embedded sdk where to navigate to. Here is the list for routes the sdk can navigate to: | Route | Description | | ------------------- | ------------------------------ | | `/flows` | Flows table | | `/flows/{flowId}` | Opens up a flow in the builder | | `/runs` | Runs table | | `/runs/{runId}` | Opens up a run in the builder | | `/connections` | Connections table | | `/tables` | Tables table | | `/tables/{tableId}` | Opens up a table | | `todos` | Todos table | | `todos/{todoId}` | Opens up a todo | ## Navigate to Initial Route You can call the `navigate` method after initializing the sdk using the `configure` sdk: ```js theme={null} const flowId = '1234'; const instanceUrl = 'YOUR_INSTANCE_URL'; const jwtToken = 'YOUR_GENERATED_JWT_TOKEN'; activepieces.configure({ instanceUrl, jwtToken, }).then(() => { activepieces.navigate({ route: `/flows/${flowId}` }) }); ``` # Overview Source: https://www.activepieces.com/docs/embedding/overview Understanding how embedding works This section provides an overview of how to embed the Activepieces builder in your application and automatically provision the user. The embedding process involves the following steps: Generate a JSON Web Token (JWT) to identify your customer and pass it to the SDK, read more [here](./provision-users). You can use the SDK to embed and customize Activepieces in your SaaS, read more [here](./embed-builder). Here is an example of how it looks like in one of the SaaS that embed Activepieces: Embedding Example In case, you need to gather connections from your users in your SaaS. You can do this with the SDK. Find more info [here](./embed-connections). If you are looking for a way to communicate between Activpieces and the SaaS embedding it through a piece, we recommend you check the [custom property doc](/build-pieces/piece-reference/properties#custom-property-beta) # Predefined Connection Source: https://www.activepieces.com/docs/embedding/predefined-connection Use predefined connections to allow users to access your piece in the embedded app without re-entering authentication credentials. The high-level steps are: * Create a global connection for a project using the API in the platform admin. Only platform admins can edit or delete global connections. * (Optional) Hide the connections dropdown in the piece settings. ### Prerequisites * [Run the Enterprise Edition](/handbook/engineering/playbooks/run-ee) * [Create your piece](/build-pieces/building-pieces/overview). Later we will customize the piece logic to use predefined connections. ### Create a Predefined Connection Go to **Platform Admin → Security → API Keys** and create an API key. Save it for use in the next step. Create API Key Add the following snippet to your backend to create a global connection each time you generate the JWT token. The snippet does the following: * Create Project If it doesn't exist. * Create a global connection for the project with certain naming convention. ```js theme={null} const apiKey = 'YOUR_API_KEY'; const instanceUrl = 'https://cloud.activepieces.com'; // The name of the user / organization in your SAAS const externalProjectId = 'org_1234'; const pieceName = '@activepieces/piece-gelato'; // This will depend on what your piece auth type is, can be one of this ['PLATFORM_OAUTH2','SECRET_TEXT','BASIC_AUTH','CUSTOM_AUTH'] const pieceAuthType = "CUSTOM_AUTH" const connectionProps = { // Fill in the props required by your piece's auth } const { id: projectId, externalId } = await getOrCreateProject({ projectExternalId: externalProjectId, apiKey, instanceUrl, }); await createGlobalConnection({ projectId, externalProjectId, apiKey, instanceUrl, pieceName, props, pieceAuthType }); ``` Implementation: ```js theme={null} async function getOrCreateProject({ projectExternalId, apiKey, instanceUrl, }: { projectExternalId: string, apiKey: string, instanceUrl: string }): Promise<{ id: string, externalId: string }> { const projects = await fetch(`${instanceUrl}/api/v1/projects?externalId=${projectExternalId}`, { method: 'GET', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, }) .then(response => response.json()) .then(data => data.data) .catch(err => { console.error('Error fetching projects:', err); return []; }); if (projects.length > 0) { return { id: projects[0].id, externalId: projects[0].externalId }; } const newProject = await fetch(`${instanceUrl}/api/v1/projects`, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ displayName: projectExternalId, metadata: {}, externalId: projectExternalId }) }) .then(response => response.json()) .catch(err => { console.error('Error creating project:', err); throw err; }); return { id: newProject.id, externalId: newProject.externalId }; } async function createGlobalConnection({ projectId, externalProjectId, apiKey, instanceUrl, pieceName, props, pieceAuthType }: { projectId: string, externalProjectId: string, apiKey: string, instanceUrl: string, pieceName: string, props: Record, pieceAuthType }) { const displayName = 'Gelato Connection'; const connectionExternalId = 'gelato_' + externalProjectId; return fetch(`${instanceUrl}/api/v1/global-connections`, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ displayName, pieceName, metadata: {}, type: pieceAuthType, value: { type: pieceAuthType, props }, scope: 'PLATFORM', projectIds: [projectId], externalId: connectionExternalId }) }); } ``` ### Hide the Connections Dropdown (Optional) Wherever you call `createTrigger` or `createAction` set `requireAuth` to `false`, this will hide the connections dropdown in the piece settings in the builder, next we need to fetch it based on a naming convention. Here is example how you can fetch the connection value based on naming convention, make sure this naming convention is followed when creating a global connection. ```js theme={null} import { ConnectionsManager, Property, TriggerStrategy } from "@activepieces/pieces-framework"; import { createTrigger } from "@activepieces/pieces-framework"; import { isNil } from "@activepieces/shared"; // Add this import from the index.ts file, where it contains the definition of the auth object. import { auth } from '../..'; const fetchConnection = async ( connections: ConnectionsManager, projectExternalId: string | undefined, ): Promise> => { if (isNil(projectExternalId)) { throw new Error('This project is missing an external id'); } // the naming convention here is gelato_projectExternalId const connection = await connections.get(`gelato_${projectExternalId}`); if (isNil(connection)) { throw new Error(`Connection not found for project ${projectExternalId}`); } return connection as PiecePropValueSchema; }; export const newFlavorCreated = createTrigger({ requireAuth: false, name: 'newFlavorCreated', displayName: 'new flavor created', description: 'triggers when a new icecream flavor is created.', props: { dropdown: Property.Dropdown({ displayName: 'Dropdown', required: true, refreshers: [], options: async (_, { connections, project }) => { const connection = await fetchConnection(connections, (await project.externalId())); // your logic return { options: [{ label: 'test', value: 'test' }] } } }) }, sampleData: {}, type: TriggerStrategy.POLLING, async test({connections,project}) { const connection = await fetchConnection(connections, (await project.externalId())); // use the connection with your own logic return [] }, async onEnable({connections,project}) { const connection = await fetchConnection(connections, (await project.externalId())); // use the connection with your own logic }, async onDisable({connections,project}) { const connection = await fetchConnection(connections, (await project.externalId())); // use the connection with your own logic }, async run({connections,project}) { const connection = await fetchConnection(connections, (await project.externalId())); // use the connection with your own logic return [] }, }); ``` # Provision Users Source: https://www.activepieces.com/docs/embedding/provision-users Automatically authenticate your SaaS users to your Activepieces instance ## Overview In Activepieces, there are **Projects** and **Users**. Each project is provisioned with their corresponding workspace, project, or team in your SaaS. The users are then mapped to the respective users in Activepieces. To achieve this, the backend will generate a signed token that contains all the necessary information to automatically create a user and project. If the user or project already exists, it will skip the creation and log in the user directly. You can generate a signing key by going to **Platform Settings -> Signing Keys -> Generate Signing Key**. This will generate a public and private key pair. The public key will be used by Activepieces to verify the signature of the JWT tokens you send. The private key will be used by you to sign the JWT tokens. Create Signing Key Please store your private key in a safe place, as it will not be stored in Activepieces. The signing key will be used to generate JWT tokens for the currently logged-in user on your website, which will then be sent to the Activepieces Iframe as a query parameter to authenticate the user and exchange the token for a longer lived token. To generate these tokens, you will need to add code in your backend to generate the token using the RS256 algorithm, so the JWT header would look like this: To obtain the `SIGNING_KEY_ID`, refer to the signing key table and locate the value in the first column. Signing Key ID ```json theme={null} { "alg": "RS256", "typ": "JWT", "kid": "SIGNING_KEY_ID" } ``` The signed tokens must include these claims in the payload: ```json theme={null} { "version": "v3", "externalUserId": "user_id", "externalProjectId": "user_project_id", "firstName": "John", "lastName": "Doe", "role": "EDITOR", "piecesFilterType": "NONE", "exp": 1856563200, "tasks": 50000, "aiCredits": 250 } ``` | Claim | Description | | ------------------ | -------------------------------------------------------------------------------------- | | externalUserId | Unique identification of the user in **your** software | | externalProjectId | Unique identification of the user's project in **your** software | | projectDisplayName | Display name of the user's project | | firstName | First name of the user | | lastName | Last name of the user | | role | Role of the user in the Activepieces project (e.g., **EDITOR**, **VIEWER**, **ADMIN**) | | exp | Expiry timestamp for the token (Unix timestamp) | | piecesFilterType | Customize the project pieces, check [customize pieces](/embedding/customize-pieces) | | piecesTags | Customize the project pieces, check [customize pieces](/embedding/customize-pieces) | | tasks | Customize the tasks limit for your user's project | | aiCredits | Customize the ai credits limit for your user's project | You can use any JWT library to generate the token. Here is an example using the jsonwebtoken library in Node.js: **Friendly Tip #1**: You can also use this [tool](https://dinochiesa.github.io/jwt/) to generate a quick example. **Friendly Tip #2**: Make sure the expiry time is very short, as it's a temporary token and will be exchanged for a longer-lived token. ```javascript Node.js theme={null} const jwt = require('jsonwebtoken'); // JWT NumericDates specified in seconds: const currentTime = Math.floor(Date.now() / 1000); let token = jwt.sign( { version: "v3", externalUserId: "user_id", externalProjectId: "user_project_id", firstName: "John", lastName: "Doe", role: "EDITOR", piecesFilterType: "NONE", exp: currentTime + (60 * 60), // 1 hour from now }, process.env.ACTIVEPIECES_SIGNING_KEY, { algorithm: "RS256", header: { kid: signingKeyID, // Include the "kid" in the header }, } ); ``` Once you have generated the token, please check the embedding docs to know how to embed the token in the iframe. # SDK Changelog Source: https://www.activepieces.com/docs/embedding/sdk-changelog A log of all notable changes to Activepieces SDK **Breaking Change:**

If your Activepieces image version is \< 0.45.0 and (you are using the connect method from the embed SDk, and need the connection externalId to be returned after the user creates it OR if you want to reconnect a specific connection with an externalId), you must upgrade your Activepieces image to >= 0.45.0
Between Acitvepieces image version 0.32.1 and 0.46.4 the navigation handler was including the project id in the path, this might have broken implementation logic for people using the navigation handler, this has been fixed from 0.46.5 and onwards, the handler won't show the project id prepended to routes. Change log format: MM/DD/YYYY (version) ### 10/27/2025 (0.8.1) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.8.1.js](https://cdn.activepieces.com/sdk/embed/0.8.1.js) * Fixed a bug where if you didn't start your navigation route with '/' it would redirect you to '/flows' ### 09/21/2025 (0.8.0) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.8.0.js](https://cdn.activepieces.com/sdk/embed/0.8.0.js) * This version requires you to **upgrade Activepieces to [0.70.0](https://github.com/activepieces/activepieces/releases/tag/0.70.0)**. * Removed `embedding.dashboard.hideSettings`. * Added `embedding.dashboard.hidePageHeader` parameter to the [configure](./embed-builder#configure-parameters) method **(value: true | false)**. ### 07/30/2025 (0.7.0) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.7.0.js](https://cdn.activepieces.com/sdk/embed/0.7.0.js) * This version requires you to **upgrade Activepieces to [0.66.7](https://github.com/activepieces/activepieces/releases/tag/0.66.7)** * Added `embedding.dashboard.hideSettings` parameter to the [configure](./embed-builder#configure-parameters) method **(value: true | false)**. ### 07/07/2025 (0.6.0) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.6.0.js](https://cdn.activepieces.com/sdk/embed/0.6.0.js) * This version requires you to **upgrade Activepieces to [0.66.1](https://github.com/activepieces/activepieces/releases/tag/0.66.1)** * Added `embedding.dashboard.hideFlowsPageNavbar` parameter to the [configure](./embed-builder#configure-parameters) method **(value: true | false)**. * **(Breaking Change)** `embedding.dashboard.hideSidebar` used to hide the navbar above the flows table in the dashboard now it relies on `embedding.dashboard.hideFlowsPageNavbar`. ### 03/07/2025 (0.5.0) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.5.0.js](https://cdn.activepieces.com/sdk/embed/0.5.0.js) * This version requires you to **upgrade Activepieces to [0.64.2](https://github.com/activepieces/activepieces/releases/tag/0.64.2)** * Added `embedding.hideDuplicateFlow` parameter to the [configure](./embed-builder#configure-parameters) method **(value: true | false)**. * Added `embedding.builder.homeButtonIcon` parameter to the [configure](./embed-builder#configure-parameters) method **(value: 'logo' | 'back')**, if set to **'back'** the tooltip shown on hovering the home button is removed. * Added `embedding.locale` parameter to the [configure](./embed-builder#configure-parameters) method, it takes [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) locale codes, here are the ones supported: **('en' | 'nl' | 'it' | 'de' | 'fr' | 'bg' | 'uk' | 'hu' | 'es' | 'ja' | 'id' | 'vi' | 'zh' | 'pt')** * Added `embedding.styling.mode` parameter to [configure](./embed-builder#configure-parameters) method **(value: 'light' | 'dark')** * **(Breaking Change)** Removed `embedding.builder.hideLogo` parameter from the [configure](./embed-builder#configure-parameters) method. * **(Breaking Change)** Removed MCP methods from sdk. ### 17/06/2025 (0.5.0-rc.1) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.5.0-rc.1.js](https://cdn.activepieces.com/sdk/embed/0.5.0-rc.1.js) * This version requires you to **upgrade Activepieces to [0.64.0-rc.0](https://github.com/activepieces/activepieces/pkgs/container/activepieces/438888138?tag=0.64.0-rc.0)** * Revert back the `prefix` parameter from the [configure](./embed-builder#configure-parameters) method. ### 16/06/2025 (0.5.0-rc.0) * SDK URL: [https://cdn.activepieces.com/sdk/embed/0.5.0-rc.0.js](https://cdn.activepieces.com/sdk/embed/0.5.0-rc.0.js) * This version requires you to **upgrade Activepieces to [0.64.0-rc.0](https://github.com/activepieces/activepieces/pkgs/container/activepieces/438888138?tag=0.64.0-rc.0)** * Added `embedding.hideDuplicateFlow` parameter to the [configure](./embed-builder#configure-parameters) method **(value: true | false)**. * Added `embedding.builder.homeButtonIcon` parameter to the [configure](./embed-builder#configure-parameters) method **(value: 'logo' | 'back')**, if set to **'back'** the tooltip shown on hovering the home button is removed. * Added `embedding.locale` parameter to the [configure](./embed-builder#configure-parameters) method, it takes [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) locale codes, here are the ones supported: **('en' | 'nl' | 'it' | 'de' | 'fr' | 'bg' | 'uk' | 'hu' | 'es' | 'ja' | 'id' | 'vi' | 'zh' | 'pt')** * Added `embedding.styling.mode` parameter to [configure](./embed-builder#configure-parameters) method **(value: 'light' | 'dark')** * **(Breaking Change)** Removed `prefix` parameter from the [configure](./embed-builder#configure-parameters) method. * **(Breaking Change)** Removed `embedding.builder.hideLogo` parameter from the [configure](./embed-builder#configure-parameters) method. ### 26/05/2025 (0.4.1) * Fixed an issue where sometimes the embed HTML file was getting cached. ### 20/05/2025 (0.4.0) \-- Note: we didn't consider adding optional new parameters as a breaking change so we were bumping the patch version, but that was wrong and we will begin bumping the minor version for those changes from now on, and patch version will only get bumped for bug fixes. * This version requires you to update Activepieces to 0.56.0 * Added `embedding.hideExportAndImportFlow` parameter to the [configure](./embed-builder#configure-parameters) method. * Added new possible value to the configure method param `embed.builder.disableNavigation` which is "keep\_home\_button\_only" that keeps only the home button and hides the folder name with the delete flow action. * Added new param to the configure method `embed.builder.homeButtonClickedHandler`, that overrides the navigation behaviour on clicking the home button. ### 17/04/2025 (0.3.7) * Added MCP methods to update MCP configurations. ### 16/04/2025 (0.3.6) * Added the [request](./sdk-server-requests) method which allows you to call our backend API. ### 24/2/2025 (0.3.5) * Added a new parameter to the connect method to make the connection dialog a popup instead of an iframe taking the full page. * Fixed a bug where the returned promise from the connect method was always resolved to \{connection: undefined} * Now when you use the connect method with the "connectionName" parameter, the user will reconnect to the connection with the matching externalId instead of creating a new one. ### 04/02/2025 (0.3.4) * This version requires you to update Activepieces to 0.41.0 * Adds the ability to pass font family name and font url to the embed sdk ### 26/01/2025 (0.3.3) * This version requires you to update Activepieces to 0.39.8 * activepieces.configure method was being resolved before the user was authenticated, this is fixed now, so you can use activepieces.navigate method to navigate to your desired initial route. ### 04/12/2024 (0.3.0) * add custom navigation handler ([#4500](https://github.com/activepieces/activepieces/pull/4500)) * allow passing a predefined name for connection in connect method ([#4485](https://github.com/activepieces/activepieces/pull/4485)) * add changelog ([#4503](https://github.com/activepieces/activepieces/pull/4503)) # API Requests Source: https://www.activepieces.com/docs/embedding/sdk-server-requests Send requests to your Activepieces instance from the embedded app **Requirements:** * Activepieces version 0.34.5 or higher * SDK version 0.3.6 or higher You can use the embedded SDK to send requests to your instance and retrieve data. Follow the instructions in the [Embed Builder](./embed-builder) to initialize the SDK. ```html theme={null} ``` **Request Parameters:** | Parameter Name | Required | Type | Description | | -------------- | -------- | ---------------------- | --------------------------------------------------------------------------------------------------- | | path | ✅ | string | The path within your instance you want to hit (we prepend the path with your\_instance\_url/api/v1) | | method | ✅ | string | The http method to use 'GET', 'POST','PUT', 'DELETE', 'OPTIONS', 'PATCH' and 'HEAD | | body | ❌ | JSON object | The json body of your request | | queryParams | ❌ | Record\ | The query params to include in your request | # Delete Connection Source: https://www.activepieces.com/docs/endpoints/connections/delete DELETE /v1/app-connections/{id} Delete an app connection # List Connections Source: https://www.activepieces.com/docs/endpoints/connections/list GET /v1/app-connections List app connections # Connection Schema Source: https://www.activepieces.com/docs/endpoints/connections/schema # Upsert Connection Source: https://www.activepieces.com/docs/endpoints/connections/upsert POST /v1/app-connections Upsert an app connection based on the app name # Get Flow Run Source: https://www.activepieces.com/docs/endpoints/flow-runs/get GET /v1/flow-runs/{id} Get Flow Run # List Flows Runs Source: https://www.activepieces.com/docs/endpoints/flow-runs/list GET /v1/flow-runs List Flow Runs # Flow Run Schema Source: https://www.activepieces.com/docs/endpoints/flow-runs/schema # Create Flow Source: https://www.activepieces.com/docs/endpoints/flows/create POST /v1/flows Create a flow # Delete Flow Source: https://www.activepieces.com/docs/endpoints/flows/delete DELETE /v1/flows/{id} Delete a flow # Get Flow Source: https://www.activepieces.com/docs/endpoints/flows/get GET /v1/flows/{id} Get a flow by id # List Flows Source: https://www.activepieces.com/docs/endpoints/flows/list GET /v1/flows List flows # Flow Schema Source: https://www.activepieces.com/docs/endpoints/flows/schema # Apply Flow Operation Source: https://www.activepieces.com/docs/endpoints/flows/update POST /v1/flows/{id} Apply an operation to a flow # Create Folder Source: https://www.activepieces.com/docs/endpoints/folders/create POST /v1/folders Create a new folder # Delete Folder Source: https://www.activepieces.com/docs/endpoints/folders/delete DELETE /v1/folders/{id} Delete a folder # Get Folder Source: https://www.activepieces.com/docs/endpoints/folders/get GET /v1/folders/{id} Get a folder by id # List Folders Source: https://www.activepieces.com/docs/endpoints/folders/list GET /v1/folders List folders # Folder Schema Source: https://www.activepieces.com/docs/endpoints/folders/schema # Update Folder Source: https://www.activepieces.com/docs/endpoints/folders/update POST /v1/folders/{id} Update an existing folder # Configure Source: https://www.activepieces.com/docs/endpoints/git-repos/configure POST /v1/git-repos Upsert a git repository information for a project. # Git Repos Schema Source: https://www.activepieces.com/docs/endpoints/git-repos/schema # Delete Global Connection Source: https://www.activepieces.com/docs/endpoints/global-connections/delete DELETE /v1/global-connections/{id} # List Global Connections Source: https://www.activepieces.com/docs/endpoints/global-connections/list GET /v1/global-connections # Global Connection Schema Source: https://www.activepieces.com/docs/endpoints/global-connections/schema # Update Global Connection Source: https://www.activepieces.com/docs/endpoints/global-connections/update POST /v1/global-connections/{id} # Upsert Global Connection Source: https://www.activepieces.com/docs/endpoints/global-connections/upsert POST /v1/global-connections # Overview Source: https://www.activepieces.com/docs/endpoints/overview API keys are generated under the platform dashboard at this moment to manage multiple projects, which is only available in the Platform and Enterprise editions, Please contact [sales@activepieces.com](mailto:sales@activepieces.com) for more information. ### Authentication: The API uses "API keys" to authenticate requests. You can view and manage your API keys from the Platform Dashboard. After creating your API key, you can pass the API key as a Bearer token in the header. Example: `Authorization: Bearer {API_KEY}` ### Pagination All endpoints use seek pagination, to paginate through the results, you can provide the `limit` and `cursor` as query parameters. The API response will have the following structure: ```json theme={null} { "data": [], "next": "string", "previous": "string" } ``` * **`data`**: Holds the requested results or data. * **`next`**: Provides a starting cursor for the next set of results, if available. * **`previous`**: Provides a starting cursor for the previous set of results, if applicable. # Install Piece Source: https://www.activepieces.com/docs/endpoints/pieces/install POST /v1/pieces Add a piece to a platform # Piece Schema Source: https://www.activepieces.com/docs/endpoints/pieces/schema # Delete Project Member Source: https://www.activepieces.com/docs/endpoints/project-members/delete DELETE /v1/project-members/{id} # List Project Member Source: https://www.activepieces.com/docs/endpoints/project-members/list GET /v1/project-members # Project Member Schema Source: https://www.activepieces.com/docs/endpoints/project-members/schema # Create Project Release Source: https://www.activepieces.com/docs/endpoints/project-releases/create POST /v1/project-releases # Project Release Schema Source: https://www.activepieces.com/docs/endpoints/project-releases/schema # Create Project Source: https://www.activepieces.com/docs/endpoints/projects/create POST /v1/projects # Delete Project Source: https://www.activepieces.com/docs/endpoints/projects/delete DELETE /v1/projects/{id} # List Projects Source: https://www.activepieces.com/docs/endpoints/projects/list GET /v1/projects # Project Schema Source: https://www.activepieces.com/docs/endpoints/projects/schema # Update Project Source: https://www.activepieces.com/docs/endpoints/projects/update POST /v1/projects/{id} # Get Sample Data Source: https://www.activepieces.com/docs/endpoints/sample-data/get GET /v1/sample-data # Create Template Source: https://www.activepieces.com/docs/endpoints/templates/create POST /v1/templates Create a template. # Delete Template Source: https://www.activepieces.com/docs/endpoints/templates/delete DELETE /v1/templates/{id} Delete a template. # Get Template Source: https://www.activepieces.com/docs/endpoints/templates/get GET /v1/templates/{id} Get a template. # List Templates Source: https://www.activepieces.com/docs/endpoints/templates/list GET /v1/templates List templates. # Template Schema Source: https://www.activepieces.com/docs/endpoints/templates/schema # Delete User Invitation Source: https://www.activepieces.com/docs/endpoints/user-invitations/delete DELETE /v1/user-invitations/{id} # List User Invitations Source: https://www.activepieces.com/docs/endpoints/user-invitations/list GET /v1/user-invitations # User Invitation Schema Source: https://www.activepieces.com/docs/endpoints/user-invitations/schema # Send User Invitation (Upsert) Source: https://www.activepieces.com/docs/endpoints/user-invitations/upsert POST /v1/user-invitations Send a user invitation to a user. If the user already has an invitation, the invitation will be updated. # Delete User Source: https://www.activepieces.com/docs/endpoints/users/delete DELETE /v1/users/{id} Delete user # List Users Source: https://www.activepieces.com/docs/endpoints/users/list GET /v1/users List users # User Schema Source: https://www.activepieces.com/docs/endpoints/users/schema # Update User Source: https://www.activepieces.com/docs/endpoints/users/update POST /v1/users/{id} Update user # Queue Metrics Source: https://www.activepieces.com/docs/endpoints/worker-machines/queue-metrics GET /v1/worker-machines/queue-metrics # Building Flows Source: https://www.activepieces.com/docs/flows/building-flows Flow consists of two parts, trigger and actions ## Trigger The flow's starting point determines its frequency of execution. There are various types of triggers available, such as Schedule Trigger, Webhook Trigger, or Event Trigger based on specific service. ## Action Actions come after the flow and control what occurs when the flow is activated, like running code or communicating with other services. In real-life scenario: Flow Parts # Debugging Runs Source: https://www.activepieces.com/docs/flows/debugging-runs Ensuring your business automations are running properly You can monitor each run that results from an enabled flow: 1. Go to the Dashboard, click on **Runs**. 2. Find the run that you're looking for, and click on it. 3. You will see the builder in a view-only mode, each step will show a ✅ or a ❌ to indicate its execution status. 4. Click on any of these steps, you will see the **input** and **output** in the **Run Details** panel. The debugging experience looks like this: Debugging Business Automations # Technical Limits Source: https://www.activepieces.com/docs/flows/known-limits Technical limits for Activepieces execution ### Execution Limits * **Flow Execution Time**\ Maximum: **600 seconds (10 minutes)**\ Flows exceeding this limit will be marked as timed out. * **Memory Usage**\ Maximum: **1 GB RAM**\ (Self hosted can be configured via `AP_SANDBOX_MEMORY_LIMIT`) The memory usage is measured for the entire Node.js process running the flow. There is approximately 300 MB of overhead for a warm process with pieces already loaded. **Note 1:** Flows paused by steps like **Wait for Approval** or **Delay** do **not** count toward the 600-second limit. **Note 2:** To handle longer processes, split them into multiple flows.\ For example: * Have one flow call another via **webhook**. * Process smaller **batches of items** in separate flows. *** ### File Storage Limits Files from actions or triggers are stored in the database/S3 to support retries for certain steps. * **Maximum File Size**: **10 MB**\ (Configurable via `AP_MAX_FILE_SIZE_MB`, default: **25 MB**) * **Maximum Flow Run Log Size**: **25 MB**\ (Configurable via `AP_MAX_FLOW_RUN_LOG_SIZE_MB`, default: **25 MB**) > This is the total combined size of all inputs and outputs for each step in a single flow run. *** ### Webhook Payload Limits * **Maximum Webhook Payload Size**: **5 MB** (Configurable via `AP_MAX_WEBHOOK_PAYLOAD_SIZE_MB`, default: **5 MB**) > Webhook payloads exceeding this limit will be rejected with HTTP 413. * **Webhook Payload Inline Threshold**: **512 KB** (Configurable via `AP_WEBHOOK_PAYLOAD_INLINE_THRESHOLD_KB`, default: **512 KB**) > Payloads below this threshold are stored inline in Redis for fastest processing. > Payloads above this threshold are offloaded to file storage to protect Redis memory. *** ### Key / Value Storage Limits Some pieces use the built-in Activepieces key store (e.g., **Store Piece**, **Queue Piece**). * **Maximum Key Length**: **128 characters** * **Maximum Value Size**: **512 KB** # Passing Data Source: https://www.activepieces.com/docs/flows/passing-data Using data from previous steps in the current one ## Data flow Any Activepieces flow is a vertical diagram that **starts with a trigger step** followed by **any number of action steps**. Steps are connected vertically. Data flows from parent steps to the children. Children steps have access to the output data of the parent steps. ## Example Steps