Integrations catalog
Appbricx ships a registry of ~200 pre-wired connectors — Slack, Gmail, Stripe, Discord, Notion, GitHub, Shopify, HubSpot, and dozens more. Connect once from workspace settings, then call them from workflows (ctx.integrations.invoke) or from generated apps via named queries. No OAuth boilerplate, no token juggling, no per-app SDK to install.
oauth2, secret_text, custom_auth, basic_auth, or none), and the actions it exposes. The vault stores credentials encrypted at rest — the browser never sees them.What integrations do
An integration is a first-class connection to an external service that your project can invoke server-side. The registry gives you:
- A single catalog UI for discovery — search by name, filter by category, one-click Connect.
- OAuth flows handled by the platform (state, PKCE, token refresh, scope negotiation).
- Encrypted credential vault — envelope encryption per workspace, with a legacy pgp_sym fallback keyed by
ENCRYPTION_KEY. - A uniform
ctx.integrations.invoke(id, action, input)runtime API — the same shape whether you are talking to Slack, Stripe, or GitHub. - Convenience helpers on
ctx.messages.*for email (Resend / SendGrid / Gmail), SMS (Twilio), WhatsApp, and Telegram.
Categories
The registry is organised into six category files. Below is a sampler — the full live list is in the catalog UI (GET /integrations/catalog).
| Category | Examples |
|---|---|
| AI / ML | Claude, OpenAI, Google Gemini, Groq, Mistral, DeepSeek, Cohere, Perplexity, Bedrock, Azure OpenAI, Vertex AI, OpenRouter, xAI Grok |
| Communication | Slack, Discord, Microsoft Teams, Gmail, Outlook, Telegram Bot, WhatsApp, Mattermost, Twilio, SendGrid, Resend |
| CRM / Marketing / Social | HubSpot, Salesforce, Pipedrive, Zoho CRM, Attio, Mailchimp, ActiveCampaign, Klaviyo, Brevo, X (Twitter), LinkedIn, Instagram Business, Facebook Pages, YouTube, Bluesky, Reddit |
| Developer tools | GitHub, GitLab, Bitbucket, Vercel, Netlify, Figma, Datadog, PostHog, LogRocket, PostgreSQL, MySQL, Bitly |
| Finance / E-commerce | Stripe, Square, PayPal, Razorpay, Mollie, Lemon Squeezy, QuickBooks, Xero, Shopify, WooCommerce, BigCommerce |
| Productivity | Notion, Airtable, Google Docs, Google Calendar, Google Drive, Google Forms, Google Tasks, monday.com, Asana, ClickUp, Trello, Todoist, Coda |
Each entry in the registry looks like this (trimmed):
{
id: "slack",
displayName: "Slack",
description: "Send messages, manage channels, react to events.",
category: "communication",
authType: "oauth2",
oauth2Config: {
authUrl: "https://slack.com/oauth/v2/authorize",
tokenUrl: "https://slack.com/api/oauth.v2.access",
scopes: ["chat:write", "channels:read", "users:read"],
},
actions: ["send_message", "create_channel", "update_message"],
tier: "built_in",
}How to connect
- Workspace admin enables the integration. In
/admin?tab=integrations, an owner or admin toggles the integrations that members of this workspace may connect. Unenabled integrations do not appear in the member-facing catalog. - Member clicks Connect. In workspace Settings → Integrations, pick the app. For
oauth2, the platform issuesGET /integrations/oauth/:id/authorize, builds the provider authorization URL (with state and PKCE where the provider requires it), and opens the provider’s consent screen. - Callback and token exchange. The provider redirects to
/integrations/oauth/callback. The server verifies state, exchanges the code for tokens, and writes anintegration_connectionsrow. - Credentials stored encrypted. Access and refresh tokens (or API keys for
secret_text/custom_authproviders) are envelope-encrypted per workspace and written tocredentials_encrypted. The browser never sees the raw values. - Available at runtime. The connection appears in
GET /integrations/connections?workspaceId=…with a status ofactiveand is immediately callable from workflows and generated apps.
authType: "secret_text" (Discord, Telegram Bot, WhatsApp, Resend, most AI keys) or custom_auth (Supabase, self-hosted Postgres, S3-compatibles) take their credentials via POST /integrations/connect as a JSON body — no browser round-trip, but the same encrypted vault path.Connection scopes
Every connection is stored at one of three scopes. Pick the narrowest one that fits — narrower scopes reduce blast radius and let members keep personal credentials personal.
| Scope | Visible to | Typical use |
|---|---|---|
workspace | Every workflow in the workspace (admin-only to create) | Shared Stripe account, shared Slack bot |
project | Workflows in one project | Project-specific Sendgrid or GitHub app |
user | Just the member who connected it | Personal Gmail, personal Notion |
Using an integration in a workflow
Workflows get an integrations namespace on ctx. The signature is uniform across every provider:
/** @param {import("@appbricx/runtime").WorkflowContext} ctx */
export async function run(ctx) {
const { email, plan } = ctx.trigger.payload ?? {};
// Charge via Stripe
const charge = await ctx.integrations.invoke("stripe", "create_payment", {
amount: plan === "pro" ? 2900 : 900,
currency: "usd",
customer_email: email,
});
// Post to Slack
await ctx.integrations.invoke("slack", "send_message", {
channel: "#signups",
text: `New ${plan} signup: ${email} (${charge?.id ?? "no id"})`,
});
// Add to HubSpot
await ctx.integrations.invoke("hubspot", "create_or_update_contact", {
email,
plan,
});
return { ok: true };
}The exact action names and input props come from the underlying Activepieces piece package. Load them from GET /integrations/catalog/:id/actions at build time, or ask the agent — it introspects the registry and generates the correctly-shaped invoke call for you.
Convenience helpers
Common messaging paths have short-form helpers on ctx.messages.*. Each is a thin wrapper over ctx.integrations.invoke:
await ctx.messages.email({
provider: "resend", // or "sendgrid" | "gmail"
to: "user@example.com",
subject: "Welcome",
html: "<h1>Hi there</h1>",
});
await ctx.messages.sms({ to: "+15555550123", body: "Your code is 4711" });
await ctx.messages.whatsapp({
to: "+15555550123",
template: "otp_login",
});
await ctx.messages.telegram({ chatId: 123456, text: "Deploy finished" });Using an integration from a generated app
Generated React apps never call third-party APIs directly — that would require shipping credentials to the browser. Instead:
- Expose the integration through a named query or a workflow. The React side calls
runtime.queries.run("name", args)orruntime.workflows.invoke("name", { payload }). - For webhooks coming from a provider (Stripe events, GitHub pushes, Slack slash-commands), point the provider at
POST /hooks/:projectId/:name— see Webhooks & schedules. - The auto-CRUD REST API and named queries can be authorised with the end-user’s session, so your workflow sees the user who triggered it via
ctx.userId.
Admin control
Integrations are per-workspace. What you see in an app’s connect catalog is the intersection of the platform-wide enablement list and the workspace’s own enablement list.
| Task | Where |
|---|---|
| Enable / disable an integration for members | /admin?tab=integrations (owner or admin) |
| Attach a workspace OAuth app (custom client ID / secret) | Admin integrations panel → Configure |
| See who has connected what | GET /integrations/connections?workspaceId=… or the admin panel |
| Revoke a connection | Member from Settings → Integrations, or admin via DELETE /integrations/connections/:id |
| Test a connection | POST /integrations/connections/:id/test — fires a lightweight authenticated ping and updates status |
Security
- Encrypted at rest. Every connection row stores credentials in
credentials_encrypted. New rows use the envelope-v1 format keyed per workspace; legacy rows usepgp_symkeyed byENCRYPTION_KEY. Reads auto-detect the format. - Never exposed to the browser. The catalog and connections endpoints return display metadata (id, displayName, scope, status) — never the token itself. All invocation happens server-side inside a workflow.
- Scoped access. A
user-scoped connection is only usable when a workflow runs on behalf of that user. Aproject-scoped connection is only usable inside that project. - Revocable. Deleting a connection removes the row and the encrypted blob. If the provider supports token revocation, it is also called on delete. Rotate
ENCRYPTION_KEYvia the operator re-encryption path. - OAuth state and PKCE. State is signed, single-use, and TTL-bound. PKCE is used automatically for providers that require or benefit from it.
- Least-privilege scopes. Registry entries list only the scopes each set of actions actually needs — no
*:read *:writecatch-alls.
Adding a custom integration
The registry is an Appbricx-side extension surface, not a runtime plugin surface. New integrations are added by editing the server registry and (usually) installing an Activepieces piece package:
- Add an entry to one of the category files under
services/api/src/integrations/registry/*.ts— or the hand-curatedservices/api/src/integrations/registry.tswhich overrides the others by ID. - Add the underlying piece package to
services/api/package.jsonsopiecePackageresolves at boot. The boot loader will silently prune any entry whose piece is not installed and log a warning. - For OAuth, set
authType: "oauth2"andoauth2Config— the platform’s OAuth flow will do the rest. For static credentials, usesecret_textorcustom_authwith acustomAuthFieldsspec. - Deploy the API. The new integration appears in the catalog at
GET /integrations/catalogand is admin-enable-able in/admin?tab=integrations.
See the developer guide for the full registry / piece / OAuth-config schema and the CI-time check-integration-pieces.mjs guard.
Related
- Workflows — the natural home for
ctx.integrations.invoke. - Webhooks & schedules — receive events from providers and fan them into workflows.
- Secrets & env — for values you would rather keep out of the integration vault entirely (webhook shared secrets, per-project API constants).
- Bring your own key — the sibling system for AI model providers, which uses its own resolution chain rather than the integration vault.