Skip to main content
Kardow Automations is a built-in workflow engine that lets you react to anything that happens on your platform and chain any number of follow-up actions — without writing custom server code for each use case. Think of it as the backbone that connects your job board to the rest of your stack: email sequences, Slack alerts, CRM syncs, subscription access on third-party platforms, and custom Cloudflare Workers you build yourself.

The core idea

Every automation has two parts:
  1. A trigger — an event that happens in your platform (a new job is posted, a user signs up, a payment succeeds, etc.)
  2. One or more actions — what happens in response (send an email, POST to a webhook, wait 24 hours, call a Cloudflare Worker, etc.)
You wire them together in the Automations section of your dashboard. Once active, they run automatically in the background for every matching event.

All available triggers

Triggers are grouped by area of your platform.

Jobs

Tip: Use job.created when you want a single automation for all new jobs. Use job.created.scraper if you want scraper imports handled separately (e.g., no notification email for automated imports).

Users

Applications

Payments & Subscriptions

Custom / External


All available actions

Each step in your workflow is one of these action types. You can chain as many as you need.

Send Email

Send a transactional email using your configured email provider. Supports template variables from the trigger payload (e.g. {{title}}, {{email}}, {{company_name}}). Config fields: To, Subject, Body (HTML) Example uses:
  • Welcome email when a new employer registers
  • “Your job has been approved” notification
  • Re-engagement email 3 days after a subscription lapses

Send Webhook

POST the trigger payload + your custom data to any external URL. Config fields: URL, HTTP method Example uses:
  • Sync new users to a CRM (HubSpot, Pipedrive)
  • Notify a Slack channel when a premium job is posted
  • Send subscription events to a billing dashboard

Wait / Delay

Pause the workflow for a set number of seconds before continuing. Powered by QStash so the delay survives server restarts — you don’t need to keep a process running. Config fields: Seconds Example uses:
  • Wait 3 days after signup before sending a “how’s it going?” email
  • Wait 1 hour after job approval before tweeting about it
  • Buffer between sequential webhook calls to avoid rate limits

HTTP Request

Make a fully custom HTTP call — any method, any URL, custom headers. Config fields: URL, Method (GET/POST/PUT/PATCH/DELETE), Headers, Body Example uses:
  • Call a Circle.so API to grant or revoke community membership
  • Hit a third-party API to post on social platforms
  • Trigger a GitHub Actions workflow

Send Notification

Send a formatted message to a Discord or Slack channel via webhook. Config fields: Webhook URL, Provider (discord/slack), Message, Title Example uses:
  • “#new-signups” channel alert with employer details
  • “#payments” alert when a subscription is cancelled
  • “#jobs” alert when a scraped job is imported

Run Worker

Call a Cloudflare Worker you built yourself. The worker receives the automation context and can do anything — custom logic, database writes, third-party API calls. Config fields: Worker URL Example uses:
  • AI-generated social post about a new job
  • Custom scoring/matching logic for applicants
  • Write to a database outside Supabase
  • Any future action type you want to add

Condition

Branch the workflow based on a field in the trigger payload. If the condition is not met, the rest of the workflow stops. Config fields: Field, Operator (equals / not_equals / contains / exists / greater_than / less_than / after_date / before_date), Value Example uses:
  • Only send a Discord alert if job.salary_type equals paid
  • Only grant Circle access if subscription.plan_type equals premium
  • Only send a re-engagement email if user.email exists
  • Only import jobs posted after a specific date

Update Record / Create Record

Write directly to your Supabase database as an automation step. Config fields: Table, Data (key-value pairs), Match column + value (for updates) Example uses:
  • Automatically set user.approved = true for users who pay
  • Create a notifications row when a new application arrives
  • Update a job’s status when its subscription expires

Fetch Data

Pull data from any external JSON API, RSS feed, or XML endpoint. The fetched items are stored in the pipeline for downstream actions (Filter, Loop, Create Record). Config fields: URL, Method (GET/POST), Format (json / xml / rss), Data Path (for JSON — the dot-notation path to the items array), Headers Example uses:
  • Pull job listings from an XML feed daily
  • Fetch new postings from a partner API
  • Import data from any REST endpoint

Filter / Transform

Filter fetched items by rules and map external field names to your internal data model. Lets you control which items make it through and how they map to Kardow fields. Config fields: Filter rules (field + operator + value), Field mapping (10 job fields: title, description, company_name, location, job_type, salary, how_to_apply, url, category, tags), Assign To (user ID), Only Import New (with date field) Operators: equals, not_equals, contains, not_contains, exists, after_date, before_date Example uses:
  • Only import jobs from today using the after_date operator on pubDate
  • Map jobTitle from an external feed to title in your job board
  • Assign all imported jobs to a specific user account
  • Filter out part-time jobs by checking job_type not_equals part-time

For Each Item (Loop)

Iterate over fetched items and run all subsequent actions once per item. Each item’s fields become available as {{field_name}} template variables in downstream actions. Config fields: None — it automatically iterates over the items from Fetch Data / Filter. Example uses:
  • Create a job record for each item in an imported feed
  • Send a notification for each new posting
  • Process each row from an API response individually

Template variables

Any text field in an action config supports {{variable}} syntax. Variables come from the trigger payload. Nested access works with dot notation: {{user.email}}, {{job.title}}.

Integration recipes

Circle.so — grant/revoke community access automatically

When a user subscribes, use the HTTP Request action to call the Circle.so API and add them to your community. When they cancel, revoke access.
For cancellations:
Effort: 10 minutes. You only need a Circle.so API key and your community ID.

Social platforms — post about new jobs

Use the Run Worker action with a Cloudflare Worker that accepts a job payload and posts to whatever platform you target (Twitter/X via their API, LinkedIn, etc.). Effort: Moderate. You need:
  • A Cloudflare Worker (50–100 lines of JavaScript)
  • API credentials for each platform
  • The platform’s OAuth app approved (LinkedIn takes a few days)
What the system provides: The trigger fires automatically on every job.created, the worker URL is configurable per automation, and you can add a Condition step to only post jobs above a certain salary or from certain categories.

Stripe / payment sync

Automations already fire on subscription.created, subscription.cancelled, and payment.succeeded from Stripe webhooks. Use the Send Webhook action to forward these events to any third-party tool in real time. For bidirectional control — e.g., cancelling a subscription from an external tool — use the external API keys system (/api/external) with the subscriptions endpoint.

HubSpot / CRM sync

Add your HubSpot private app token in the Headers field.

Scheduled data imports

The data import pipeline lets you automatically pull jobs (or any data) from external sources on a schedule.

How it works

A scheduled import automation uses four actions in sequence:

Step-by-step setup

  1. Go to Automations in your dashboard
  2. Select Scheduled Job Import from the Scheduled category
  3. Set the trigger interval (e.g. Daily at 6 AM UTC)
  4. In Fetch Data, paste your source URL and select the data format:
    • JSON: Set the data path to the array key (e.g. results.jobs)
    • RSS/XML: Items are extracted automatically from <item> or <entry> tags
  5. In Filter / Transform:
    • Add filter rules (e.g. status equals active, pubDate after_date today)
    • Map your external fields to Kardow fields (e.g. jobTitletitle, companyNamecompany_name)
    • Set Assign To to the user who should own the imported jobs
    • Toggle Only Import New to skip items older than today
  6. The For Each Item and Create Record steps are pre-configured
  7. Activate the automation

Cron setup

Add an hourly cron job (Vercel Cron, GitHub Actions, or any scheduler) that calls:
The endpoint checks each scheduled automation’s interval and only runs it when it’s due.

Supported data formats


What Kardow Automations is good at

  • Reacting to platform events with zero infrastructure overhead
  • Chaining multiple steps including delays (backed by QStash — no cron jobs to manage)
  • Connecting to any external API via webhook or HTTP request
  • Extending with custom Cloudflare Workers for logic too specific to bake in
  • Full run analytics: every execution is logged with status, timing, and error details

Current limitations

These are the current boundaries of the system. Some are planned improvements, some are by design.

Planning for subscriptions, communities & monetization

Resume database access

The payments and paywall system supports plan-gated content today. To gate a resume database:
  1. Create a payment plan with a specific code (e.g., resume_access)
  2. Use the Paywall feature to restrict the resume section to subscribers of that plan
  3. Use an automation (subscription.created) to send them a welcome email or grant access to external tools

Custom communities (Circle.so or built-in)

Circle.so integration: Works today via HTTP Request actions as described above. Full sync in both directions is possible with one automation per event (subscription.created, subscription.cancelled). Built-in community features: Not in the current system. Would require new pages and a roles/access layer. The role system (employer, candidate, admin) is extensible — new roles can be added — but a full community module (posts, threads, spaces) would be a separate feature build.

Multi-plan role permissions

The current subscription system supports plan types and job quotas. Expanding to role-based feature flags (e.g., “only users on the community plan can see the forum”) can be done today by:
  1. Checking user_subscriptions.plan_type in your pages
  2. Using automations to sync plan type to a user_metadata field for fast client-side access

Adding new trigger points

Any existing route can fire an automation in one line:
No new API routes needed. No configuration changes. The engine finds all active automations for that event and org and runs them.

Adding new action types

To add a new action type (e.g., post_to_twitter):
  1. Add the key to AutomationActionType in lib/automations/types.ts
  2. Add its label and description to ACTION_TYPES
  3. Add a case 'post_to_twitter': block in the executeAction switch in lib/automations/engine.ts
  4. Add a config form in AutomationsClient.tsx
That’s it. The UI, API, and run logging all pick it up automatically.

Security notes

  • Automations are scoped to a single organization. You can never trigger another org’s automations.
  • All run logs (including payloads) are protected by RLS — only members of the org can read them.
  • Webhook URLs and HTTP request targets are user-supplied — validate them in your config and consider allowlisting domains for sensitive actions.
  • The trigger endpoint (/api/automations/trigger) uses admin Supabase access — it should not be called from client-side code.