diff --git a/brain/knowledge/engineering/engineering-handbook-playbooks.md b/brain/knowledge/engineering/engineering-handbook-playbooks.md
index 9539672cecbf..30eb1a950856 100644
--- a/brain/knowledge/engineering/engineering-handbook-playbooks.md
+++ b/brain/knowledge/engineering/engineering-handbook-playbooks.md
@@ -22,3 +22,4 @@ Postmortems (Redis/queue overload, infra upgrade — March 2026) and product int
## Gotchas
- **`DISCORD_ON_CALL_WEBHOOK` is the single repo secret behind every on-call Discord notification** — cloud production deploys (`continuous-delivery-cloud.yml`), self-hosted releases (`release-self-hosted.yml`), and release-pieces failure alerts all post through it. Rotating it repoints all of them at once; there is no per-workflow webhook. Self-hosted release notifications skip `-rc` tags unless `publish_rc_release` is set, mirroring the release-drafter condition so the message never links a release page that doesn't exist.
+- **Docs media lives on the CDN, never in the repo — and videos and images sit on two different paths.** A video embeds as ``, an image as ``. Videos are namespaced under `videos/docs/`; images are **flat** under `assets/` with no `docs/` segment, so don't infer one path from the other — check the URL you actually mean. Both mirror the filename verbatim, so an upload is fetchable with no config change. Committing the binary instead bloats every clone forever (`docs/videos/` reached 63 MB and `docs/images/` 1.6 MB before both were removed in Sept 2026) since git history keeps the blob even after a delete. Curl each URL for a 200 before deleting a local copy: `docs/` also carries stale `.mdx` references to images that never existed in git history at all, and rewriting one of those to a CDN URL turns a visibly-missing asset into a confident 404.
diff --git a/brain/knowledge/pieces-engine/building-pieces.md b/brain/knowledge/pieces-engine/building-pieces.md
index ef85061e294e..f50e8a424978 100644
--- a/brain/knowledge/pieces-engine/building-pieces.md
+++ b/brain/knowledge/pieces-engine/building-pieces.md
@@ -26,6 +26,8 @@ Authentication, triggers (polling/webhook), properties + validation, flow contro
- **Pass the whole `context` to `pollingHelper`, never `{ store, auth, propsValue }`.** The destructured form is the dominant shape in the repo (306 of 403 `onEnable` call sites) and it type-checks, so it reads as idiomatic — but the helper's param type is wider than those three fields, and TypeScript only rejects excess properties, never missing optional ones. So each field added to the polling context is silently absent in every destructuring trigger. `context.isRepublish` is the first one that changes behaviour: `pollingHelper.onEnable` uses it to keep the existing `lastPoll`/`lastItem` instead of resetting to now, so a destructuring trigger still drops every event between its last poll and a republish ([triggers.md](../flows-execution/triggers.md) has the platform-side thread). Scaffolding (`npm run cli triggers create`), `docs/build-pieces/`, and the piece-builder skill all pass `context`, so new triggers are fine — the trap is copying from a neighbouring piece, since the wrong shape is the majority there. The legacy sites are being fixed **on touch** rather than by one repo-wide codemod: whoever edits a piece switches that piece's calls over, which rides an existing version bump and rebuild instead of forcing one on ~300 pieces nobody is running.
- **Porting postgres `new-row.ts` to another SQL piece: the `LIMIT 5` is cold-start only — do not carry it onto the resume branch.** `constructQuery` (`postgres/src/lib/triggers/new-row.ts:41`) has two shapes, and the asymmetry between them is load-bearing: the no-checkpoint branch seeds with `ORDER BY %I DESC LIMIT 5` (`:46,48`), while the resume branch is deliberately **unbounded** — `WHERE %I >= %L ORDER BY %I DESC`, no LIMIT (`:58,60`). It has to be, because `DedupeStrategy.LAST_ITEM` (`:17`) recovers the checkpoint by scanning *the page it just fetched* (`pieces/common/src/lib/polling/index.ts:99`, `items.findIndex((f) => f.id === lastItemId)`) and emits everything ahead of it. Bound the resume page and the checkpoint row can fall off the end, where `findIndex → -1` is read as "no checkpoint" and the entire page re-emits ([triggers.md](../flows-execution/triggers.md) has the same mechanic from the republish side). So a literal `LIMIT 5` → `TOP (5)` is a behaviour change, not a dialect translation — and the moment you *do* want a bounded resume page you are off `pollingHelper` altogether and owe a keyset cursor that carries its position in the store instead of recovering it by scanning: `microsoft-sql-server/src/lib/common/cursor.ts` is the worked example (`TOP (@limit)` on every page, versioned cursor, explicit tiebreaker key). Two more sharp edges if you copy this template: the item id is `orderValue + '|' + md5(JSON.stringify(row))` (`:24-28`), so **any edit to the checkpoint row changes its id and invalidates the checkpoint**, and `lastItem.split('|')[0]` (`:42`) truncates any order value containing a literal `|` — fine for timestamps and serial ids, wrong for ordering on a text column.
- **Streaming a file *into* a piece is `Property.File({ streaming: true })`.** It resolves to an `ApStreamingFile` with `body: Readable` (pieces-framework ≥ 0.35.0, [000014](../../decisions/000014-streaming-file-inputs-resolve-to-a-lazy-apstreamingfile.md)) and accepts a URL, a base64 data URL, the builder's file picker, or a previous step's file — a strict superset of a URL text field, with the fetch owned by the engine. `amazon-s3/upload-file.ts` and `subflows/stream-csv-to-flow.ts` are the references. Three things to know: the engine's `fileProcessor` swallows fetch failures and returns `null`, which for a `required: true` prop surfaces as the confusing `Expected file url or base64 with mimeType` validation error rather than a fetch error (so no `isNil` guard in your `run()` is needed — the action never starts); the engine's fetch has **no timeout**, so a source that connects then stalls burns `FLOW_TIMEOUT_SECONDS`; and `.pipe()` does not forward `'error'`, so you still need `file.body.on('error', ...)` or a mid-stream network drop becomes an uncaught exception in the sandbox.
+- **A piece's `validate()` catch block swallows engine failures as invalid connections unless you explicitly re-throw.** The auth server context hands `validate()` a `mintOidcToken({ audience })` callback whose engine-side implementation calls the internal `/v1/worker/oidc-token` endpoint; when that endpoint 5xxs, the engine throws a `PieceServerContextError` (from `@activepieces/pieces-framework`). It looks like any other `Error`, so a naive `try { await getTemporaryCredentials(...) } catch (e) { return { valid: false, error: format(e) } }` reports the platform outage as `INVALID_APP_CONNECTION` — user sees "your connection is bad", oncall gets no page. The contract every OIDC piece must follow is `if (isPieceServerContextError(error)) throw error;` before the catch's return; `executeValidateAuth` (`packages/server/engine/src/lib/helper/piece-helper.ts`) re-wraps it as `EngineGenericError`, which `tryCatchAndThrowOnEngineError` routes as `ExecutionErrorType.ENGINE` and pages. The reference implementations are the four AWS OIDC pieces (`amazon-bedrock`, `aws-bedrock`, `amazon-s3`, `amazon-secrets-manager`) — same shape in all of them. Runtime paths (executing a step, refreshing a token) intentionally do NOT go through this class — a runtime OIDC failure fails one step as a user-level error, which is correct because a persistent platform issue would show up across many flows and be caught operationally.
+- **AWS region strings flow into the STS endpoint hostname.** The `@aws-sdk/client-sts` builds the STS endpoint URL by interpolating `sts..amazonaws.com`, and does not itself check the shape. A crafted region like `us-east-1.evil.com` redirects the STS call to an attacker-controlled host — a real SSRF-shaped issue since the piece runs in the engine sandbox with outbound network access and the JWT it's about to send is a valid, platform-signed OIDC token. Validate the region against `/^[a-z]{2}(-[a-z]+)+-\d$/` **before** any code that touches it (before minting the OIDC token, before building the STS client, before the cache key). All four AWS OIDC pieces enforce this in `getTemporaryCredentials`. The same shape applies to any AWS SDK client built with a user-controlled region.
- **Streaming only removes *our* memory ceiling — check the destination's per-request cap before calling an upload action fixed.** A body that streams cleanly out of the sandbox still gets rejected whole by the API: Dropbox's `/2/files/upload` answers `409 {".tag": "payload_too_large"}` above 150 MB, Graph's simple `PUT …/content` above 250 MB. The tell that it's the service and not us is the shape — an endpoint-specific 409 with a documented error tag, and an axios/undici request echo whose `body` is just a `_readableState` blob (our stream, sent fine). The fix is a chunked upload session, not a bigger buffer: `dropbox/upload-file.ts` and `microsoft-onedrive/upload-file.ts` are the references, both chunking through the shared `streamUtils.readChunks({ readable, chunkSize })` from `@activepieces/pieces-common` — reuse it rather than writing a third stream chunker. Two rules that fall out of doing it: **route unknown-size sources through the session too** (`size` is best-effort and absent on chunked or compressed sources, so you cannot prove they fit — and the old fallback of buffering to learn the size is the OOM this streaming work exists to remove), and keep the chunk size a multiple of the service's preferred unit (4 MiB for Dropbox, 320 KiB for OneDrive). Chunk bodies are `Buffer`s, so unlike a one-shot stream body they keep `httpClient`'s retries. **Whether you can chunk an unknown-size source at all depends on how the session addresses its parts:** Dropbox's is offset-based (`cursor.offset`, no total ever declared) so it streams straight through, while Graph's wants the file's total length in every fragment's `Content-Range` — so `microsoft-sharepoint` and `microsoft-onedrive` must `readableToBuffer` once to learn the length, then re-wrap with `Readable.from` so both branches still take a stream. That buffer is the OOM this work removes, so it is a last resort, not the pattern: reach for the offset-based session whenever the API offers one. SharePoint's cap is generous enough (250 MB one-shot vs OneDrive's 4 MiB) that the buffer only ever runs for a size-less source.
- **On Windows, a new action/trigger name (or any metadata-shape change) needs the dev server process killed, not restarted.** `clearPieceModuleCache` — the only thing that busts the CommonJS `require()` cache backing dev piece metadata — is called exclusively from the chokidar watcher's rebuild handler (`dev-piece-watcher.ts`), and that watcher does not fire reliably on Windows for tool-made edits. A "normal restart" reuses the same PID (confirm with `netstat`/`Get-Process` bound to the dev port), so the server keeps serving the stale metadata. Find the PID bound to the dev API port and `Stop-Process -Id -Force`, then start fresh — every other change (prop text, logic inside `run()`) hot-reloads fine; only new action/trigger names or output-shape changes hit this.
- **`Property.Array`'s `properties` sub-schema never threads into its resolved `propsValue` type — confirmed in `packages/pieces/framework/src/lib/property/index.ts`.** `propsValue.someArrayProp` types as plain `unknown[]` regardless of what `properties` declares, so casting to the declared row type at the point of use is the only option; there is no framework-provided type-safe path around it. Document the cast in a comment so it doesn't read as an oversight on a later pass.
diff --git a/bun.lock b/bun.lock
index 8ed1d4b8a2d4..36b37c98e2a0 100644
--- a/bun.lock
+++ b/bun.lock
@@ -163,7 +163,7 @@
},
"packages/core/shared": {
"name": "@activepieces/shared",
- "version": "0.156.0",
+ "version": "0.157.0",
"dependencies": {
"@activepieces/core-execution": "workspace:*",
"@activepieces/core-formula": "workspace:*",
diff --git a/docker-compose.yml b/docker-compose.yml
index 14254b283d8c..14e746aa5c59 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,6 @@
services:
app:
- image: ghcr.io/activepieces/activepieces:0.90.0
+ image: ghcr.io/activepieces/activepieces:0.90.1
container_name: activepieces-app
restart: unless-stopped
ports:
@@ -16,7 +16,7 @@ services:
networks:
- activepieces
worker:
- image: ghcr.io/activepieces/activepieces:0.90.0
+ image: ghcr.io/activepieces/activepieces:0.90.1
restart: unless-stopped
depends_on:
- app
diff --git a/docs/about/changelog.mdx b/docs/about/changelog.mdx
index 6dbd52ce8b27..cae20fa6675d 100755
--- a/docs/about/changelog.mdx
+++ b/docs/about/changelog.mdx
@@ -21,7 +21,7 @@ name, brief, talk to, and reuse.
and adds one that sends, posts or files only when the sentence asks for it.
- **Edit with AI**: describe a change in the editor — *"only reply to paying customers"* —
and the instructions and tools are rewritten for you. Edits stay a draft until you press
- **Save and go live**, and going live updates every flow already using the agent on its
+ **Publish**, and publishing updates every flow already using the agent on its
next run, with nothing to republish.
**Where an agent lives**
diff --git a/docs/admin-guide/guides/ai-capabilities.mdx b/docs/admin-guide/guides/ai-capabilities.mdx
new file mode 100644
index 000000000000..1412a7705b5c
--- /dev/null
+++ b/docs/admin-guide/guides/ai-capabilities.mdx
@@ -0,0 +1,52 @@
+---
+title: "AI Capabilities"
+icon: "bicep"
+---
+
+AI Capabilities let platform admins connect external services that give the Activepieces AI assistant additional abilities beyond what the AI model can do on its own.
+
+Currently, you can configure capabilities for **Web Search, Web Scraping, and Image Generation**.
+
+### **Why use AI Capabilities?**
+
+AI Capabilities let your organization control which external services the AI assistant can use for specialized tasks.
+
+For example, you can allow the assistant to search for current information on the web, extract content from webpages, or generate images when users need these capabilities.
+
+Configuring these services at the platform level also means the required API credentials can be managed centrally rather than asking individual users to configure them.
+
+### **Available AI Capabilities**
+
+#### **Web Search**
+
+Web Search lets the AI assistant search the live web for current information.
+
+This is useful for tasks where the assistant needs information that may not be available in the model itself.
+
+#### **Web Scraping**
+
+Web Scraping lets the AI assistant extract clean content from webpages as Markdown, including pages that are rendered with JavaScript.
+
+This can be useful when the assistant needs to read and work with the full content of a webpage rather than just search results.
+
+#### **Image Generation**
+
+Image Generation lets the AI assistant create images such as realistic photos, marketing graphics with text, brand logos, and abstract art. The model is selected automatically for each request.
+
+### **How To Set Up AI Capability**
+
+The setup is similar across the available capabilities:
+
+1. Go to **Platform Admin → AI Center → AI Capabilities**.
+2. Find the capability you want to configure.
+3. Click **Set up**.
+4. Enter the API key for the external service.
+5. Click **Save**.
+
+
+
+### **AI Providers vs AI Capabilities**
+
+**AI Providers** connect the AI models Activepieces uses, while **AI Capabilities** connect external services that give the AI assistant additional abilities such as web search, web scraping, and image generation.
+
+
diff --git a/docs/admin-guide/guides/connections.mdx b/docs/admin-guide/guides/connections.mdx
new file mode 100644
index 000000000000..bcd0c7dca19f
--- /dev/null
+++ b/docs/admin-guide/guides/connections.mdx
@@ -0,0 +1,44 @@
+---
+title: "Connections"
+icon: "chain"
+---
+
+Connections are the individual accounts of third-party apps or integrations connected to your Activepieces platform.
+
+For example, when a user connects their Gmail account to Activepieces, that account is registered as one connection. If two users connect their individual Gmail accounts, Activepieces registers them as two separate connections, even though they both use the same Gmail piece.
+
+**Example:**
+
+Employee 1 Gmail **=** Connection 1
+
+Employee 2 Gmail **=** Connection 2
+
+
+
+The Connections page in Platform Admin gives administrators a detailed view of all app connections across every project on the platform. You can filter connections by **name, status, piece, project, and owner**.
+
+For each connection, you can see:
+
+- Its current status
+- The piece or app it belongs to
+- The project and owner associated with it
+- When the connection was created
+- The scope (whether it is available to specific projects or is a **Global Connection**)
+
+If it is a Global Connection, you can also see the different projects that have access to that connection.
+
+Learn more about [Connections vs Global Connections](https://app.mintlify.com/activepieces/activepieces/editor/ginika%2Fdraft-aug-31/~/766e454b-da15-4ea1-9e26-de1c537fc45b)
+
+As more teams build automations, the number of connected accounts can grow quickly. The Connections page gives platform admins a single place to see which accounts are connected, who owns them, where they are used, and whether they are still active.
+
+For example, if an employee leaves the company, an admin can use the **Owner** filter to identify connections associated with that user and understand which projects may depend on them.
+
+Regularly reviewing connections can also help identify outdated ones
+
+### **Navigating Connections Via API**
+
+Refer to [API reference](https://www.activepieces.com/docs/endpoints/connections/schema)
+
+
+
+
diff --git a/docs/admin-guide/guides/general.mdx b/docs/admin-guide/guides/general.mdx
new file mode 100644
index 000000000000..0b46a1c24abf
--- /dev/null
+++ b/docs/admin-guide/guides/general.mdx
@@ -0,0 +1,14 @@
+---
+title: "General"
+icon: "gears"
+---
+
+This is where you can change the basic appearance of your platform
+
+You can change the platform name, icon, logo , fav icon url, primary color, or customize your theme colors
+
+You also have the **Danger Zone,** which is where you can delete your platform.
+
+**NB:** Once your platform is deleted, it cannot be recovered. Ensure you cancel your subscription before deleting your platform.
+
+
diff --git a/docs/admin-guide/guides/global-connections.mdx b/docs/admin-guide/guides/global-connections.mdx
new file mode 100644
index 000000000000..0172489fd870
--- /dev/null
+++ b/docs/admin-guide/guides/global-connections.mdx
@@ -0,0 +1,74 @@
+---
+title: "Global Connections"
+icon: "globe"
+---
+
+Global Connections enable platform admins to create and manage connections to external apps that can be shared across multiple projects.
+
+Instead of every project or user creating a separate connection to the same account, an organization can create one connection and make it available to the projects that need it.
+
+For example, if several departments need to send emails from the same company Gmail account, an admin can create it as a Global Connection and give the appropriate projects access to it.
+
+### **Viewing Global Connections**
+
+The **Global Connections** page gives platform admins an overview of the global connections configured on the platform.
+
+For each connection, you can see:
+
+- **Name**: The app or integration connected
+- **Status**: Whether the connection is currently active
+- **Connected At**: When the connection was created
+- **Projects**: How many projects have access to the connection
+
+You can also search for connections and filter them by status.
+
+### **Create a Global Connection**
+
+You can create a new global connection using either
+
+- **OAuth2**: Quickly connect using a preconfigured OAuth2 app. No setup required.
+- **Custom OAuth2 App (Advanced)**: Connect using your own OAuth2 credentials for more flexibility and control.
+
+- **Service Account (Advanced):** Connect using service account credentials for secure, non-user-based access to an external application.
+
+**OAuth2**
+
+**Step 1**: Go to **Platform Admin → Global Connections**.
+
+**Step 2**: Click **New Connection**.
+
+**Step 3**: Select the app you want to connect.
+
+**Step 4**: Select which projects the connection should be available for
+
+**Step 5**: Select if you want that connection to be included by default in new projects
+
+**Step 6**: Select the permissions you want that connection to have
+
+**Step 7**: Click Connect and follow the authentication instructions
+
+**Step 8:** Click Save
+
+
+
+#### **Custom OAuth2 App (Advanced) or Service Account (Advanced)**
+
+**Step 1**: Go to **Platform Admin → Global Connections**.
+
+**Step 2**: Click **New Connection**.
+
+**Step 3**: Select the app you want to connect.
+
+**Step 4**: Click **Try another method**
+
+**Step 5:** Select **Custom OAuth2 App (Advanced)** or **Service Account (Advanced)** depending on what you want
+
+You can search for Global Connections by typing the name of the connection in the search bar
+
+You can also filter them by **Status**: Active, Error, or Missing.
+
+### **Global Connections vs Connections**
+
+A **Connection** is one account connected to Activepieces, such as a user's Gmail or Slack account. It is available only in the project where it was created. The Connections page in Platform Admin gives admins a central place to view and filter connections from all projects across the platform.
+
+A **Global Connection** is a shared connection that a platform admin can make available to multiple projects in the platform. Use it when different projects need to use the same account without creating a separate connection for each project.
diff --git a/docs/admin-guide/guides/manage-pieces.mdx b/docs/admin-guide/guides/manage-pieces.mdx
index bfbed3c3f78f..d073ac29b783 100644
--- a/docs/admin-guide/guides/manage-pieces.mdx
+++ b/docs/admin-guide/guides/manage-pieces.mdx
@@ -1,5 +1,5 @@
---
-title: "How to Manage Pieces"
+title: "Pieces"
description: "Control which integrations are available to your users"
icon: "puzzle-piece"
---
@@ -19,12 +19,12 @@ As a platform administrator, you have full control over which pieces are availab
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 |
-Pieces are standard npm packages — official pieces are **auto-synced from the registry hourly**, so you don't need to upgrade the server to get new versions. Each step in a flow is pinned to a specific piece version, and drafts can be upgraded from the builder. See [Piece Syncing & Versioning](/install/architecture/piece-syncing) for the full pipeline.
+ Pieces are standard npm packages — official pieces are **auto-synced from the registry hourly**, so you don't need to upgrade the server to get new versions. Each step in a flow is pinned to a specific piece version, and drafts can be upgraded from the builder. See [Piece Syncing & Versioning](/install/architecture/piece-syncing) for the full pipeline.
---
@@ -45,6 +45,7 @@ Project administrators can further restrict which pieces are available within th
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
@@ -53,29 +54,28 @@ Project administrators can further restrict which pieces are available within th
-
-
+
-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.
+ 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.
+ 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
npm run pieces -- build --name=your-piece-name
```
+
This generates a tarball in `dist/packages/pieces/your-piece-name`.
diff --git a/docs/admin-guide/guides/permissions.mdx b/docs/admin-guide/guides/permissions.mdx
index 23668aff47f4..7a1b795d729e 100644
--- a/docs/admin-guide/guides/permissions.mdx
+++ b/docs/admin-guide/guides/permissions.mdx
@@ -1,38 +1,61 @@
---
-title: "Manage User Roles"
-description: "Documentation on project permissions in Activepieces"
-icon: 'user'
+title: "Users"
+icon: "user"
---
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
+The Users tab is a dedicated place for your platform admin to manage, delete, activate, and deactivate users at the entire platform level, not just from projects.
+
+### How To Invite a User To Your Platform
+
+**Step 1**: Click on Users in the platform admin
+
+**Step 2**: Navigate to the upper right and click the **invite** button
+
+**Step 3**: Add the invitee’s email and assign them a role
+
+**Step 4:** Click **Invite**
+
+
+
+### **How To Edit User Role**
+
+**Step 1**: Go to Users in the platform admin
+
+**Step 2**: Click on the 3 dots to the right of the user you want to edit
+
+**Step 3**: Click on Edit
+
+
+
+####
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** |||||
+| --- | :-: | :-: | :-: | :-: |
+| **Flows** | | | | |
| View Flows | ✓ | ✓ | ✓ | ✓ |
-| Edit Flows | ✓ | ✓ | | |
-| Publish / Toggle Flows | ✓ | ✓ | ✓ | |
-| **Runs** |||||
+| Edit Flows | ✓ | ✓ | | |
+| Publish / Toggle Flows | ✓ | ✓ | ✓ | |
+| **Runs** | | | | |
| View Runs | ✓ | ✓ | ✓ | ✓ |
-| Retry Runs | ✓ | ✓ | ✓ | |
-| **Connections** |||||
+| Retry Runs | ✓ | ✓ | ✓ | |
+| **Connections** | | | | |
| View Connections | ✓ | ✓ | ✓ | ✓ |
-| Edit Connections | ✓ | ✓ | ✓ | |
-| **Team** |||||
+| Edit Connections | ✓ | ✓ | ✓ | |
+| **Team** | | | | |
| View Project Members | ✓ | ✓ | ✓ | ✓ |
-| Add/Remove Project Members | ✓ | | | |
-| **Git Sync** | | | | |
-| Configure Git Repo | ✓ | | | |
-| Pull Flows from Git | ✓ | | | |
-| Push Flows to Git | ✓ | | | |
+| Add/Remove Project Members | ✓ | | | |
+| **Git Sync** | | | | |
+| Configure Git Repo | ✓ | | | |
+| Pull Flows from Git | ✓ | | | |
+| Push Flows to Git | ✓ | | | |
-## Custom Roles
+#### Custom Roles
If the default roles don't fit your needs, you can create custom roles with specific permissions.
@@ -49,5 +72,32 @@ If the default roles don't fit your needs, you can create custom roles with spec
-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.
-
\ No newline at end of file
+ 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.
+
+
+### **Deactivate & Delete User:**
+
+**Step 1**: Click on Users in the platform admin
+
+**Step 2**: Click on the 3 dots to the right of the user you want to delete or deactivate
+
+**Step 3:** Click on either Delete or Deactivate depending on what you want
+
+
+
+**_NB_**:
+
+- If you **Deactivate a user**, they will lose access but won't lose all their data. You can always activate them again.
+- However, if you **Delete** a user, all their data will be deleted as well.
+
+### **Managing users in larger organizations**
+
+For larger teams, managing users one by one can quickly become difficult. Instead, you can use [**Single Sign-On (SSO)**](https://app.mintlify.com/activepieces/activepieces/editor/ginika%2Fdraft-aug-31/~/dbcb5d11-21d1-444b-bd97-4a062786a2ec) to let users sign in with your organization’s identity provider and [**SCIM**](https://app.mintlify.com/activepieces/activepieces/editor/ginika%2Fdraft-aug-31/~/e1d21d0e-a53d-478d-9f6b-d788b5f01576) to automate user provisioning and deprovisioning.
+
+This makes it easier to manage access as your organization grows without manually inviting, activating, or deactivating every user.
+
+### **Navigating Users Via API**
+
+Refer to [API reference](https://www.activepieces.com/docs/endpoints/users/schema)
+
+
diff --git a/docs/admin-guide/guides/setup-ai-providers.mdx b/docs/admin-guide/guides/setup-ai-providers.mdx
index 99ba50c97a96..f004698509cb 100644
--- a/docs/admin-guide/guides/setup-ai-providers.mdx
+++ b/docs/admin-guide/guides/setup-ai-providers.mdx
@@ -1,53 +1,129 @@
---
-title: "Setup AI Providers"
+title: "AI Providers"
description: "Bring your own AI keys and use them across every project"
icon: "sparkles"
---
-AI providers are configured once by the platform admin, with your own keys. Every project then gets [AI pieces](https://www.activepieces.com/pieces/ai), agents, and AI steps without anyone else handling a credential.
+AI Providers lets platform administrators connect the AI services that can be used by [AI pieces](https://www.activepieces.com/pieces/ai).
-## How to set one up
+Instead of every user adding their own provider credentials, an administrator can configure supported providers centrally and make them available for use across the platform.
-Go to **Platform Admin** → **AI Center**, pick a provider, and add your key. The setup screen carries the exact steps for getting a key from that provider.
+### **Why use AI Providers?**
-
+AI Providers gives organizations one place to control which AI services are connected to Activepieces.
+
+This is especially useful for larger teams that want to:
+
+- Use company-managed AI provider accounts instead of personal accounts
+- Keep provider credentials managed centrally
+- Standardize which AI providers teams use
+- Apply company security and access policies to AI usage
+
+### **How Connect to an AI Provider**
+
+**Step 1**: Go to **Platform Admin → AI Center →AI Providers**.
+
+**Step 2:** Find the provider you want to configure.
+
+**Step 3**: Click **Connect**.
+
+**Step 4**: Follow the instructions shown for that provider and enter the required credentials.
+
+**Step 5**: Click **Save**.
+
+Once configured, the provider can be used by supported AI features in Activepieces.
+
+
## Supported providers
+ **Gateways**
+
+ * OpenRouter
+ * Cloudflare AI Gateway
+
+ **Anything else**
+
+ * Other (OpenAI Compatible)
+
-**Other (OpenAI Compatible)** covers any endpoint that speaks the OpenAI API, including self-hosted models and gateways not listed here. Point it at your own base URL.
+ **Other (OpenAI Compatible)** covers any endpoint that speaks the OpenAI API, including self-hosted models and gateways not listed here. Point it at your own base URL.
## Cost control and logging
+Spend on your own key goes to your provider, so put a gateway in front of it when you want limits and an audit trail:
+
+- Set rate limits and budgets
+- Log and monitor every AI request
+- Track usage across projects
+
+**OpenRouter** and **Cloudflare AI Gateway** are set up like any other provider. Any other gateway that speaks the OpenAI API works through **Other (OpenAI Compatible)**, so LiteLLM, Portkey, Helicone, and self-hosted routers are all fine.
+
+## Supported providers
+
+
+