Inline Task Triggers
Define cron or event triggers directly in task() — serve() auto-registers on deploy
Event Fan-out
publishEvent() dispatches to all matching event triggers simultaneously
HTTP Webhooks
POST to any URL on a schedule — works with Python, Go, Ruby, any language
Full CRUD
Create, pause, resume, fire, and delete triggers via SDK or console
Source types and Target types
Sources: cron (time-based), event (named event via publishEvent)
Targets: task (TypeScript handler), http (any URL), run (container — coming soon)
Inline Cron Trigger (Recommended)
The simplest way: define the trigger inside your task. serve() automatically registers it when your app first starts — fully idempotent.
import { task, serve } from '@sylphx/sdk/tasks'
export const dailyCleanup = task({
id: 'daily-cleanup',
trigger: { cron: '0 2 * * *' }, // fires every day at 2am UTC
run: async (_, { step }) => {
await step.run('delete-sessions', () =>
db.sessions.deleteMany({ where: { updatedAt: { lt: daysAgo(30) } } })
)
await step.run('notify', () =>
slack.send('#ops', 'Daily cleanup complete')
)
},
})
// app/api/tasks/route.ts — serve() calls TriggersClient.create() on first request
export const { GET, POST } = serve({ tasks: [dailyCleanup] })Event Triggers
Fire tasks when something happens in your app — user signs up, order is placed, payment fails. Fan-out to multiple handlers from a single publishEvent() call.
import { task, serve } from '@sylphx/sdk/tasks'
import { TriggersClient, createConfig } from '@sylphx/sdk'
// Handler A — sends welcome email
export const sendWelcomeEmail = task({
id: 'send-welcome-email',
trigger: { event: 'user.signup' },
run: async ({ userId }, { step }) => {
const user = await step.run('fetch', () => db.users.findUnique({ where: { id: userId } }))
await step.run('email', () => mailer.welcome(user.email, user.name))
},
})
// Handler B — sync to CRM
export const syncToCrm = task({
id: 'sync-to-crm',
trigger: { event: 'user.signup' },
run: async ({ userId, plan }) => {
await crm.contacts.upsert({ externalId: userId, plan })
},
})
// From your auth handler — both tasks fire automatically
const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })
await TriggersClient.publishEvent(config, 'user.signup', {
userId: newUser.id,
plan: newUser.plan,
email: newUser.email,
})HTTP Triggers (any language)
Schedule a POST to any URL — no TypeScript required. Your Python/Go/Ruby service just needs an HTTP endpoint.
import { TriggersClient, createConfig } from '@sylphx/sdk'
const config = createConfig({
secretKey: process.env.SYLPHX_SECRET_KEY!,
ref: process.env.SYLPHX_PROJECT_REF!,
})
// Cron → HTTP
await TriggersClient.create(config, {
name: 'nightly-backup',
source: { type: 'cron', expression: '0 3 * * *' },
target: {
type: 'http',
url: 'https://my-python-service.internal/api/backup',
headers: { Authorization: `Bearer ${process.env.INTERNAL_SECRET}` },
payload: { type: 'full', compress: true },
},
idempotencyKey: 'nightly-backup-v1', // prevents duplicates across deploys
})
// Event → HTTP
await TriggersClient.create(config, {
name: 'notify-slack-on-payment',
source: { type: 'event', eventName: 'payment.succeeded' },
target: {
type: 'http',
url: 'https://hooks.slack.com/services/xxx/yyy/zzz',
payload: { text: 'Payment received! 💰' },
},
})Managing Triggers
import { TriggersClient, createConfig } from '@sylphx/sdk'
const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })
// List all triggers
const { triggers } = await TriggersClient.list(config)
// Get a specific trigger
const trigger = await TriggersClient.get(config, 'sched_abc123')
// Pause / Resume
await TriggersClient.pause(config, trigger.id)
await TriggersClient.resume(config, trigger.id)
// Fire immediately (one-shot, regardless of schedule)
await TriggersClient.fire(config, trigger.id)
// Update schedule
await TriggersClient.update(config, trigger.id, {
source: { type: 'cron', expression: '0 4 * * *' }, // move from 3am to 4am
})
// Delete
await TriggersClient.delete(config, trigger.id)API Reference
| Property | Type | Description |
|---|---|---|
source.typerequired | "cron" | "event" | When to fire: cron = time-based, event = named event trigger. |
source.expression | string | Standard 5-field cron expression (when source.type = "cron"). |
source.eventName | string | Event name to listen for (when source.type = "event"). e.g. "user.signup". |
target.typerequired | "task" | "http" | What to dispatch to. |
target.taskName | string | Task ID to dispatch (when target.type = "task"). |
target.url | string | URL to POST to (when target.type = "http"). |
idempotencyKey | string | Optional dedup key — prevents duplicate trigger creation per project. |
paused | boolean | Create in paused state (default: false — active immediately). |
TriggersClient.publishEvent()
| Property | Type | Description |
|---|---|---|
eventNamerequired | string | Name of the event. Matches against all active event triggers. |
payload | Record<string, unknown> | Data forwarded to all matching handlers. Merged with trigger base payload. |
Event payload merging
{...triggerPayload, ...eventPayload, _event: { name, publishedAt }}. Use _event.name to know which event fired your task.