Backends & Data

Scheduled flows and backend logic for your app

Backends let an app run code on a schedule in start.chat’s cloud. They’re the bridge between external services and your workspace — fetching data, processing webhooks, sending notifications, and keeping everything in sync without anyone lifting a finger.

Most apps use suggestedFlowsAndBlocks inside createApp() to seed install-time automation threads. Suggested flows can run actions on a schedule and call your existing actions. A standalone backend export is for custom scheduled logic that doesn’t fit into the action model (e.g. multi-step syncs, cursor-based pagination, or work that spans several data calls).

Defining a backend

Export a backend object from your app with a schedule and a run function:

export const backend = {
runsEvery: '15 minutes',
async run({ tools }) {
const res = await fetch('https://api.example.com/status')
const json = await res.json()
await tools.data.public.set('status', JSON.stringify(json), {
title: 'Current Status',
kind: 'status',
})
},
}

The runsEvery property accepts intervals from '10 seconds' up to '1 day'. The run function receives a context object with the tools described below.

Run context

PropertyDescription
toolsAPIs for data, messaging, AI, and more
optionsUser-configured app options
controllerAbort controller for cancellation
oauthTokenOAuth token if the app uses OAuth

See Tools API for the complete tools reference.

Sandbox

Backends run in a sandboxed environment with access to fetch, timers, URL/URLSearchParams, console, Buffer, TextEncoder/TextDecoder, btoa/atob, and the Web Crypto API. No direct filesystem access — all external communication goes through fetch.

Example

A backend that syncs GitHub repositories and sends a workspace notification:

export const backend = {
runsEvery: '15 minutes',
async run({ tools, oauthToken }) {
const res = await fetch('https://api.github.com/user/repos', {
headers: { Authorization: `Bearer ${oauthToken}` },
})
const repos = await res.json()
for (const repo of repos.slice(0, 10)) {
await tools.data.public.set(`repo:${repo.id}`, JSON.stringify(repo), {
title: repo.full_name,
kind: 'repository',
tags: [repo.private ? 'private' : 'public'],
})
}
tools.notify(`Synced ${repos.length} repositories`)
},
}