Skip to Content
AutomateCustom Services

Custom Services

Custom Services are JavaScript modules stored in the database and shared across extensions, cron jobs, and event hooks. They eliminate code duplication for common tasks like calling external APIs, sending notifications, or computing derived values.

Database Schema (daas_custom_services)

ColumnTypeDescription
iduuidPrimary key
nametextUnique identifier used in services.custom('name')
descriptiontextHuman-readable description
codetextJavaScript module code
testsjsonbArray of test case objects
last_test_runjsonbResult of the most recent test run
statustextactive, inactive, draft, or error
dependenciestext[]Names of other custom services this one depends on
timeout_msintegerMaximum execution time in ms
versionintegerAuto-incremented on each save

Test case schema

[ { "name": "sends notification", "description": "Should send a Slack message", "code": "const result = await api.call('notify', '#channel', 'Hello'); assert.ok(result.ok);" } ]

Last test run schema

{ "status": "passed", "passed": 3, "failed": 0, "total": 3, "duration_ms": 142, "ran_at": "2025-01-15T10:00:00Z", "ran_by": "user-uuid", "results": [ { "name": "sends notification", "status": "passed", "duration_ms": 48 } ] }

Writing a Custom Service

A custom service is a module that receives a context argument and returns a plain object of named functions. The context object exposes the same platform services available in extensions and cron jobs.

// Slack notification service return { notify: async function(channel, message) { const res = await context.services.fetch('https://slack.com/api/chat.postMessage', { method: 'POST', headers: { Authorization: `Bearer ${context.env.SLACK_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ channel, text: message }), }); return res.json(); }, notifyUser: async function(userId, message) { const svc = await context.services.items('daas_users'); const user = await svc.readOne(userId, { fields: ['email'] }); return this.notify(user.email, message); }, };

Using a Custom Service

Call services.custom('name') inside any extension, cron job, or event hook:

// Inside an extension export function register(sdk) { sdk.emitter.onAction('articles.items.update', async (meta, context) => { if (meta.payload?.status === 'published') { const slack = await context.services.custom('slack-notify'); await slack.notify('#content', `Article published: ${meta.key}`); } }); }
// Inside a cron job const emailer = await services.custom('email-digest'); await emailer.sendWeeklyDigest();

Service Dependencies

If service A depends on service B, list B in A’s dependencies array. The executor resolves and injects all dependencies before running the service.

REST API

MethodPathDescription
GET/api/servicesList custom services
POST/api/servicesCreate custom service
GET/api/services/:idGet a service
PATCH/api/services/:idUpdate a service
DELETE/api/services/:idDelete a service
POST/api/services/:id/testsRun the service’s tests
Last updated on