SDK
Event Handlers
Register BEFORE and AFTER hooks, subscribe to events, watch metrics.
BEFORE Hooks (Gerund)
Validate, transform, or reject before an action executes:
import { Contact } from '@headlessly/crm'
import { Subscription } from '@headlessly/billing'
Contact.qualifying(contact => {
if (!contact.email) throw new Error('Cannot qualify without email')
return contact
})
Subscription.creating(sub => {
if (!sub.plan) throw new Error('Plan is required')
return { ...sub, startDate: new Date() }
})AFTER Hooks (Past Tense)
React to completed actions. The $ context is available as a second argument for cross-entity access:
import { Contact, Deal } from '@headlessly/crm'
import { Ticket } from '@headlessly/support'
Contact.qualified(contact => {
console.log(`${contact.name} qualified -- schedule follow-up`)
})
Deal.closed((deal, $) => {
$.Subscription.create({ plan: 'pro', contact: deal.contact })
$.Contact.update(deal.contact, { stage: 'Customer' })
})
Ticket.created((ticket, $) => {
if (ticket.priority === 'High') {
$.Agent.deploy({ template: 'support-bot', ticket: ticket.$id })
}
})Event Stream
Subscribe to all events or filter by type:
import { $ } from '@headlessly/sdk'
// All events
$.events.subscribe('*', event => { /* ... */ })
// Specific entity
$.events.subscribe('Contact.*', event => { /* ... */ })
// Specific action
$.events.subscribe('Deal.Closed', event => { /* ... */ })Metric Watches
React when metrics cross thresholds:
import { Metric, Goal } from '@headlessly/analytics'
import { Campaign } from '@headlessly/marketing'
Metric.watch('churn_rate', { threshold: 3.0, direction: 'above' }, () => {
Campaign.create({ name: 'Win-back', segment: 'churning' })
})
Metric.watch('mrr', { threshold: 100_000, direction: 'above' }, () => {
Goal.complete({ id: 'goal_hR5tLnYm' })
})