Appearance
Context API
run(ctx) receives one argument, ctx.
| Property | Hook type | Description |
|---|---|---|
ctx.http | PULL, PUSH | HTTP client |
ctx.secrets | PULL, PUSH | The integration's credentials |
ctx.org | PULL, PUSH | Organisation metadata |
ctx.kv | PULL, PUSH | Key-value store scoped to the hook |
ctx.log | PULL, PUSH | Log entries on the execution record |
ctx.meta | PULL | Pagination state from the previous page |
ctx.event | PUSH | The change that triggered the run |
ctx.http
ts
ctx.http.get(url, options?)
ctx.http.delete(url, options?)
ctx.http.post(url, body, options?)
ctx.http.put(url, body, options?)
ctx.http.patch(url, body, options?)Each method returns a response. Use await.
js
const resp = await ctx.http.get('https://hr.example.com/api/v1/employees', {
headers: { Authorization: `Bearer ${ctx.secrets.API_KEY}` },
query: { limit: '100' },
});
if (resp.status !== 200) throw new Error(`HR API returned ${resp.status}`);
const employees = resp.body.data;Arguments
| Argument | Type | Description |
|---|---|---|
url | string | Absolute http: or https: URL. |
body | any | post, put and patch only. A string is sent as it is; any other value is sent as JSON. |
options.headers | object | Request headers, as strings. A User-Agent header is ignored. |
options.query | object | Query parameters, as strings. Each replaces a parameter of the same name already in url. |
options.timeout | number | Milliseconds. Defaults to 60000, which is also the maximum. |
When a request has a body and no Content-Type header, Content-Type: application/json is added.
Every request is sent with User-Agent: Flowstate-CustomIntegration/1.0.
Response
| Property | Type | Description |
|---|---|---|
status | number | HTTP status code. |
headers | object | Response headers. Names are lower case. |
body | any | Parsed JSON when the content-type header contains application/json and the body parses. Otherwise the body as a string. |
A non-2xx status is returned, not thrown. Check status.
Errors
A call throws when:
- the run has used its 50 requests (per page for PULL, per run for PUSH). Every call counts, including calls that throw.
- the URL isn't a valid
http:orhttps:URL. - the destination is a private network,
localhostor a cloud metadata endpoint. - the server responds with a redirect. Redirects aren't followed.
- the response is larger than 10 MB.
- the request times out or the connection fails.
Each request made is listed on the execution's HTTP Log with its method, URL, status and duration.
ctx.secrets
A plain object holding the integration's credentials, keyed by credential key.
js
const token = ctx.secrets.API_KEY;- Keys are UPPER_SNAKE_CASE: a capital letter, then capitals, digits or underscores.
- Values are strings. A key that isn't set is
undefined. - A changed value applies from the next run.
- Secret values that appear in log messages, log data, error messages or logged URLs are replaced with
[REDACTED]. Values shorter than three characters aren't masked.
Credentials are managed in the app. See Store credentials.
ctx.org
Read-only.
| Property | Type | Description |
|---|---|---|
id | string | Organisation ID |
name | string | Organisation name |
timezone | string | IANA time zone, such as Europe/London |
currency | string | Reporting currency, ISO 4217, such as GBP |
ctx.kv
A string key-value store that persists between runs.
js
const cursor = await ctx.kv.get('cursor'); // string or null
await ctx.kv.set('cursor', nextCursor); // expires after 90 days
await ctx.kv.set('lock', '1', 3600); // expires after 3,600 seconds| Method | Returns | Description |
|---|---|---|
get(key) | string or null | null when the key is missing, has expired, or holds an empty string. |
set(key, value, ttlSeconds?) | — | Stores value, replacing any existing value and its expiry. |
| Rule | Detail |
|---|---|
| Scope | One store per hook. Dry runs and real runs share it. |
| Keys | 1–256 characters. Anything else throws. |
| Values | Strings of up to 64 KB (65,536 bytes as UTF-8). A non-string or larger value throws. Use JSON.stringify for structured data. |
| Expiry | ttlSeconds in whole seconds. Omitted or 0: 90 days. |
| Deleting | There's no delete. Overwrite the value, or set a short ttlSeconds. |
ctx.log
js
ctx.log.info('Fetched page', { page: 3, count: 100 });
ctx.log.warn('Employee has no email; skipped', { id: 'E-1042' });
ctx.log.error('Unexpected response', { status: resp.status });| Argument | Type | Description |
|---|---|---|
message | string | Converted to a string. |
data | any | Optional. Must be JSON-serialisable. |
Each entry is stored with a timestamp and level (info, warn or error), and shown on the Console tab and in Execution History. Output from console isn't captured.
ctx.meta
PULL hooks only. The meta object the previous page returned, or undefined on the first page. See Pagination.
undefined in PUSH hooks.
ctx.event
PUSH hooks only. The change that triggered the run.
| Property | Type | Description |
|---|---|---|
entityType | string | The hook's entity type |
entityId | string | Flowstate ID of the changed record |
changeType | string | create, update or delete |
before | object or null | The record before the change. null for create. |
after | object or null | The record after the change. null for delete. |
What before and after contain for each entity type: PUSH hooks.
undefined in PULL hooks.
Globals
Standard JavaScript built-ins such as JSON, Math, Date, Promise and Intl are available.
These aren't: fetch, setTimeout, URL, TextEncoder, atob, crypto, Buffer, structuredClone, require and process. Use ctx.http for network requests.