Appbricx
Docs
PricingStart free

Start here

OverviewGetting startedProjects & editorBring your own key

End-to-end walkthroughs

Lead intakeMulti-user TodoMulti-tenant SaaSReal-time ChatSlack on signup

AI & keys

AI keys — how resolution worksBYOK deep dive

SDK reference

Frontend SDK — @app/sdkBackend SDK — @app/backendUI kit — @app/ui

Integrations

Integrations catalog

Full-stack runtime

Runtime overviewNamed queriesAuth & RLSAuto CRUD REST APIWorkflowsWebhooks & schedulesTopics & CDCData templatesSecrets & env

Ship & own

Publish & domainsExport & GitHubSelf-host & deploy

Developers

Developer guide

Ship a Slack alert on new signup end-to-end

A focused walkthrough for adding a real integration to an app you already have. Pick any Appbricx project with end-user signup, connect Slack, write one CDC-triggered workflow, then simulate the trigger without waiting for a real user to sign up.

0. Assumptions

  • You already have a project generated by Appbricx with end-user auth (Auth & RLS). Any of the lead intake or multi-user todo walkthroughs give you one.
  • Your app has a users (or equivalent) table into which a signup writes a row. Adjust the table name below if yours differs — the pattern is the same.

1. Connect Slack in one click

  1. Open the project → Integrations.
  2. Find Slack, click Connect, and finish the OAuth handshake to your workspace.
  3. Pick the default channel the integration should post into (for example #signups). Note the channel id — the workflow can override it per call, but a default keeps the code short.

Catalog + wire protocol details: Integrations.

2. Add a CDC binding

Fire a workflow every time a row is inserted into users. Edit (or create) .appbricx/backend/cdc/bindings.json:

{
  "bindings": [
    {
      "id": "users-insert-slack",
      "table": "users",
      "ops": ["insert"],
      "topic": null,
      "workflow": "notify-slack-on-signup"
    }
  ]
}

Prefer runtime.upsert_cdc_binding if you have an editor script — DB + file stay aligned. Background on CDC: Topics & CDC.

3. Write the workflow

Create .appbricx/backend/workflows/notify-slack-on-signup.workflow.js:

/** @param {import("@appbricx/runtime").WorkflowContext} ctx */
export async function run(ctx) {
  const row = ctx.trigger.payload?.row;
  if (!row?.email) return { ok: true, skipped: true };

  // Optional enrichment — total signups so far, for a nicer message.
  const totalR = await ctx.queries.run("count_users");
  const total  = totalR.rows?.[0]?.count ?? null;

  const text = total != null
    ? `New signup: ${row.email} (${row.name ?? "no name"}) — #${total} overall`
    : `New signup: ${row.email} (${row.name ?? "no name"})`;

  // ctx.integrations.invoke — provider + action; connection is resolved
  // from the workspace integration set up in step 1.
  const res = await ctx.integrations.invoke("slack", "chat.postMessage", {
    channel: "#signups",
    text,
    blocks: [
      { type: "section", text: { type: "mrkdwn", text: `*${text}*` } },
      { type: "context", elements: [
        { type: "mrkdwn", text: `user_id: \`${row.id}\`` },
      ]},
    ],
  });

  if (!res.ok) throw new Error(res.error ?? "slack post failed");
  ctx.log.info(`posted signup notice for ${row.email}`);
  return { ok: true, ts: res.ts };
}

Two things worth pointing out:

  • ctx.integrations.invoke(provider, action, args) is the universal shape for every catalog integration. Slack, Resend, Gmail, Notion, Linear — they all follow that call signature. See the ctx cheat sheet.
  • The workflow throws when Slack returns ok: false. That marks the run as failed in app_runtime_runs, so you can spot post-failures in Backend → Runs without reading logs.

4. Simulate a signup — do not wait for a real user

Two ways to fire the workflow before shipping to production users.

a) Invoke the workflow directly

Fastest — same code path as CDC, without needing to insert a row:

# SDK
await runtime.workflows.invoke("notify-slack-on-signup", {
  payload: {
    row: { id: "u_demo", email: "demo@example.com", name: "Demo User" },
  },
});

# HTTP
curl -sS -X POST "$ORIGIN/__appbricx/runtime/workflows/notify-slack-on-signup/run" \
  -H "Authorization: Bearer $DATA_TOKEN" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{"payload":{"row":{"id":"u_demo","email":"demo@example.com","name":"Demo"}}}'
# → { "ok": true, "runId": "…" }

b) Insert a real row and let CDC fire it

Better for end-to-end confidence — exercises the CDC binding you added in step 2.

curl -sS -X POST "$ORIGIN/__appbricx/api/v1/users" \
  -H "Authorization: Bearer $DATA_TOKEN" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{"email":"cdc@example.com","name":"CDC Test"}'

Both variants land as a row in Backend → Runs. Auto CRUD reference: Auto CRUD REST API.

5. Inspect the run + logs

curl -sS "$ORIGIN/__appbricx/runtime/runs/$RUN_ID" \
  -H "Authorization: Bearer $DATA_TOKEN" \
  -H "x-appbricx-data-api: 1"

# Response shape (trimmed):
# {
#   "run": {
#     "id": "run_...", "workflow_id": "notify-slack-on-signup",
#     "trigger_type": "cdc", "status": "succeeded",
#     "started_at": "...", "finished_at": "...",
#     "result": { "ok": true, "ts": "1712345678.001200" }
#   },
#   "logs": [
#     { "level": "info", "msg": "posted signup notice for demo@example.com" }
#   ]
# }

Everything you see here is also available in the editor via Backend → Runs — same shape, easier to browse.

6. Optional — wrap the workflow in a webhook for external callers

Handy if a non-Appbricx system (Zapier, another SaaS, a cron on a laptop) also needs to trigger the alert. Add a webhook manifest and point it at the same workflow:

// .appbricx/backend/webhooks/notify-signup.json
{
  "id": "notify-signup",
  "name": "notify-signup",
  "workflow": "notify-slack-on-signup",
  "secret_ref": "WEBHOOK_SECRET",
  "enabled": true
}

Put the secret value into project env / vault under WEBHOOK_SECRET. See Secrets & env.

curl -sS -X POST "$ORIGIN/hooks/$PROJECT_ID/notify-signup" \
  -H "content-type: application/json" \
  -H "x-appbricx-webhook-secret: $WEBHOOK_SECRET" \
  -d '{"row":{"id":"u_ext","email":"ext@example.com","name":"External"}}'
# → { "ok": true, "runId": "…" }

Public route mechanics + rate limits: Webhooks & schedules.

Internal map (what just happened)

INSERT INTO users(...)
  → CDC emit (insert on 'users')
  → binding "users-insert-slack" enqueues workflow run
  → runner loads notify-slack-on-signup.workflow.js
  → ctx.queries.run("count_users")      (optional enrichment)
  → ctx.integrations.invoke("slack", "chat.postMessage", {...})
  → Slack Web API                       (auth from workspace connection)
  → run status + logs in app_runtime_runs
Reusing this pattern. Swap Slack for Resend, Gmail, Notion, Linear, or any other catalog integration — the CDC binding, the workflow shape, and the two test paths (direct invoke + real insert) stay identical. That is the whole point of ctx.integrations.invoke: one call signature, one hundred destinations.
Appbricx

Full-stack AI app builder for teams. Hosted cloud or private deploy into your account — multi-tenant, sandboxed, credit-metered.

Product

How it worksDemoCapabilitiesPricingPrivate cloudBYOKFAQ

Resources

DocumentationBlogFor freelancersFor agenciesSupport

Company

ContactPrivate cloud / agencyPrivacyTerms

© 2026 Appbricx. All rights reserved.

TermsPrivacyCookiesAcceptable Use