Triggers, Routes & Jobs
Register Cloud Code callbacks, HTTP routes, background jobs, and backend extensions.
Callbacks (Before & After Triggers)
Use callbacks to react to object lifecycle events regardless of where the change originates (storefront, backend, API). Register handlers with Nimbu.Cloud.before(event, [scope], handler) or Nimbu.Cloud.after(...).
Supported Events
| Object | Before Events | After Events |
|---|---|---|
| Channel entries | channel.entries.created, channel.entries.updated, channel.entries.deleted | Same as before events |
| Coupons | coupon.created, coupon.updated, coupon.deleted | Same as before events |
| Customers | customer.created, customer.updated, customer.deleted | Same as before events |
| Devices | device.created, device.updated, device.deleted | Same as before events |
| Products | product.created, product.updated, product.deleted | Same as before events |
| Orders | — | order.created, order.updated, order.canceled, order.fulfilled, order.paid, order.reopened, order.attachments.ready, order.attachments.expired |
For channel events you can scope the callback to a specific channel slug:
Nimbu.Cloud.after('channel.entries.created', 'blog', (request, response) => {
// request.object is the new entry
});Request & Response Objects
Inside callbacks you receive:
request.object– The mutated object (channel entry, customer, product, etc.).request.actor– Customer or backend user who triggered the change.request.changes– Hash of modified fields with[oldValue, newValue]tuples (only for update/delete).response.success()/response.error()– Accept or reject the change. Provide a message orfield, messageto attach validation errors inbeforecallbacks.
Use response.error('field', 'Message') in before hooks to block persistence when business rules fail. You can also mutate values by calling request.object.set('field', value) before the object is saved.
Cloud Functions
Define callable functions with Nimbu.Cloud.define('functionName', handler). Use them from Cloud Code (Nimbu.Cloud.run) or the REST API. Handlers receive (request, response):
Nimbu.Cloud.define('addLoyaltyPoints', async (request, response) => {
const customer = request.user; // when authenticated
await customer.increment('loyalty_points', request.params.points);
response.success({ ok: true });
});Routes (HTTP Endpoints)
Expose custom HTTP endpoints using Nimbu.Cloud.get, post, put, patch, delete, or the generic route(verb, path, handler).
Nimbu.Cloud.get('/newsletter', (request, response) => {
response.render('newsletter_form');
});
Nimbu.Cloud.post('/newsletter', async (request, response) => {
await Nimbu.Object.extend('newsletter_subscriptions').create({ email: request.params.email });
response.redirect('/thank-you');
});Supported path patterns:
/foo/bar– Static paths./orders/:id– Named parameters available viarequest.params.id./*path– Glob patterns for catch-all routes.
Routes run with the same session awareness as the storefront. Use request.user or request.customer to act on behalf of authenticated users, and call request.session to inspect session data when needed.
Background Jobs
Register jobs with Nimbu.Cloud.job('name', handler) for long-running tasks. Schedule them with Nimbu.Cloud.schedule(name, data, timing) where:
data– JSON-serializable payload accessible asrequest.params.timing– Choose one of:{ at: new Date(...) }– Run at a specific timestamp.{ in: '600s' }– Run after a delay (supportss,m,h).{ every: '0 * * * *' }– Cron expression for recurring jobs.{}– Run immediately.
Unschedule jobs by passing the same data payload, optionally with at:
Nimbu.Cloud.unschedule('nightly_sync', { siteId: 'abc' });
Nimbu.Cloud.unschedule('nightly_sync', { siteId: 'abc' }, { at: new Date('2025-12-24T23:00:00Z') });Jobs receive request.params only; there is no actor context. Use them for bulk API calls, integrations, or scheduled exports. All job invocations obey the same timeout safeguards as routes.
Scheduler Utilities
At runtime, scheduler calls flow through Nimbu.Cloud.internal.schedule, unschedule, and testCrontab. Call Nimbu.Cloud.modules.scheduler.test(cronExpression) to validate cron syntax (see the Scheduler class for details).
Backend Extensions
Extend the Nimbu admin UI with buttons that trigger Cloud Code:
Nimbu.Cloud.extend('order.show', { name: 'Resend invoice' }, async (request, response) => {
await request.object.resendInvoice();
response.success('Invoice queued for delivery');
});Available Extension Targets
| View | Description |
|---|---|
channel.entries.list | List view for channel entries. Optional channel slug to limit scope. |
channel.entries.show | Detail view for a specific channel entry. Optional slug filter. |
collection.list / collection.edit | Product collections index and detail. |
coupon.list / coupon.edit | Coupon lists and detail. |
customer.list / customer.show | Customer management views. |
order.list / order.show | Order overviews and detail pages. |
product.list / product.show | Product management views. |
Inside the handler:
request.object– The entity being acted on (only present forshow/edit).request.params– Form values (reserved for future use).request.actor– Backend user metadata (name,email,role).
Respond with:
response.success(message)– Show a green notification.response.error(message)– Show an error toast.response.redirect_to(urlOrPath, { success, error })– Redirect and show optional flash messages.
Practical Patterns
- Combine callbacks and jobs: trigger a job from a callback when expensive work is needed.
- Use before callbacks to enforce invariants (e.g., block deleting a product with pending orders).
- Keep route handlers lean; delegate heavy lifting to functions or jobs for reusability.
- Wrap integrations in
try/catchand respond withresponse.errorto propagate failures to the storefront/user. - Remember that callbacks run even when data changes via API imports—guard against infinite loops by checking
request.actoror inspectingrequest.changes.
With routing and lifecycle events covered, move on to Runtime APIs for a deep dive into request objects, sessions, and helper utilities.