Appearance
hailer.activity
Read and write activities (the records inside workflows), and print documents from them.
| Method | Host op | Returns |
|---|---|---|
list(processId, phaseId, options?) | activity.list | Promise<Activity[]> |
get(activityId) | activity.get | Promise<Activity | undefined> |
create(workflowId, activities, options?) | activity.create | Promise<Activity[]> |
update(activities, options?) | activity.update | Promise<number> |
remove(activities) | activity.remove | Promise<number> |
print(requests, options?) | activity.print | Promise<PrintResponse> |
Addressing by key
Wherever a method takes a workflow, phase, or field, it accepts either the generated _id or that item's key — a stable, human-defined name set in the workspace configuration. This lets an app work against a workflow without hard-coding ids. See the Keys guide for the full model and constraints.
list—processIdandphaseIdaccept an id or a key.create— the workflow argument, each activity'sphaseId, and the field keys insidefieldsaccept an id or a key.update—phaseIdand the field keys insidefieldsaccept an id or a key. (Activities are still identified by_id.)
Resolving a workflow key requires a workspaceId, because keys are unique per workspace. Pass it in the options object. Ids never need a workspaceId.
list(processId, phaseId, options?)
ts
// By id
const byId = await hailer.activity.list(workflowId, phaseId, { limit: 50 });
// By key (workspaceId resolves the workflow key)
const byKey = await hailer.activity.list('support_tickets', 'open', {
limit: 50,
workspaceId,
});options is an ActivityListOptions (sort, paging, includes).
get(activityId)
ts
const activity = await hailer.activity.get(activityId);Takes only the activity id. (Activities have no key; get them from list.)
create(workflowId, activities, options?)
Create one or more activities in a workflow.
ts
// By id
const created = await hailer.activity.create(workflowId, [
{ name: 'Ticket A', fields: { [fieldId]: 'High' }, phaseId, teamId },
]);
// By key — workflow key, phase key, and field keys, with workspaceId
const created2 = await hailer.activity.create('support_tickets', [
{ name: 'Ticket B', fields: { priority: 'High' }, phaseId: 'open' },
], { workspaceId });Each entry is { name?, fields?, phaseId?, teamId? }. Field values follow ActivityFieldValue. Resolves with the created activities.
update(activities, options?)
ts
const count = await hailer.activity.update([
{ _id: activityId, fields: { priority: 'Closed' } }, // field key or id
]);Each entry must carry an _id. Field keys inside fields accept a key or id; phaseId accepts a key or id. A field value of null clears the field. Resolves with the number of activities updated.
remove(activities)
ts
const count = await hailer.activity.remove([id1, id2]);Takes an array of activity ids and resolves with the number removed.
print(requests, options?)
Generate documents (PDF/CSV) from activities using their workflow's document templates.
ts
// Single regular template — may be saved to the activity
const result = await hailer.activity.print([
{ activityId, templateId, savePdf: true },
]);
// Multiple activities / templates — merged output
const merged = await hailer.activity.print([
{ activityId: a, templateId: t1 },
{ activityId: b, templateName: 'Invoice' },
]);Each request is { activityId, templateId?, templateName?, savePdf? }. Behavior:
- Single regular template (one request with
templateIdand notemplateName) generates one document.savePdfonly applies in this case — it saves the generated PDF back to the activity. - Multiple requests, or any
templateName(multi-PDF) produce a single merged document and are never saved. AtemplateNameresolves a multi-PDF template from the activity's field data; the same template can appear more than once when authored in the array format.
Opening the document on the device (openNative)
Inside the Hailer Android app, an app's frame can't print or display a PDF itself (blob: and data: URLs stay in the WebView, which has no PDF viewer). Pass { openNative: true } to have Hailer open the generated document in the device's own viewer instead, where the user can print or share it. On Android the document is also saved to the device's Downloads.
ts
const result = await hailer.activity.print([{ activityId, templateId }], { openNative: true });
if (!result.openedNatively) {
// Web, iOS, or an older Hailer version: handle result.data yourself, as before
}openedNativelyistruewhen the document was handed to the device's viewer,falsewhen the host can't do that here (web, iOS). Older Hailer versions ignore the option and leave the field unset, so treat anything buttrueas "not opened".- The document data is returned in both cases, so the fallback needs no second request.
- Without the option,
printbehaves exactly as before.
See PrintRequest / PrintOptions / PrintResponse.
hailer.activity.kanban
| Method | Host op | Returns |
|---|---|---|
list(processId, options?) | activity.kanban.list | Promise<KanbanListResponse> |
load(activityId) | activity.kanban.load | Promise<KanbanLoadResponse> |
updatePriority(activityId, priority) | activity.kanban.updatePriority | Promise<void> |
ts
const board = await hailer.activity.kanban.list(workflowId);
await hailer.activity.kanban.updatePriority(activityId, 3);list options follow ActivityKanbanListOptions.
hailer.activity.ball
The "ball" is Hailer's turn/assignment marker on an activity's discussion.
| Method | Host op | Returns |
|---|---|---|
pass(activityId, toUserId) | activity.ball.pass | Promise<void> |
take(activityId) | activity.ball.take | Promise<void> |
list(discussionIds) | activity.ball.list | Promise<BallHolderEntry[]> |
ts
await hailer.activity.ball.pass(activityId, userId);
await hailer.activity.ball.take(activityId);
const all = await hailer.activity.ball.list('*');
const some = await hailer.activity.ball.list([discussionId]);list accepts an array of discussion ids or '*' for all. It is served from the host's in-memory ball cache (kept current via ball signals), so there is no server round-trip. Passing an empty array resolves to [] without a call. See BallHolderEntry.
Ball changes are also delivered as signals (activity.ball.passed, taken, cleared, autoAssigned).