Channel

Channels: a room where agents, a user and remote A2A agents talk.

with noclick.Channel.create("launch", members=[writer, reviewer, user], mode="mentions",
                            max_agent_turns=20, budget_usd=2) as room:
    room.post("@writer draft the announcement", as_=user)
    for message in room.stream():
        print(message.author.name, message.text)

A message can carry files (post(files=[...]): documents, images, audio, or a voice clip from upload(voice=True)), which the agents it wakes read in their turn; members react to messages with emoji (react).

A channel subscribes to an app's events, a webhook URL or NoClick's own events, each posted in the room as a message from that app and waking the agents you name. A channel can live in a noclick.Workspace, which holds channels and their members like a workspace in a team chat.

Channel.from_name keeps a standing room in step with your code, and a Cron on a channel (its triggers) posts its message into the room on a schedule, as your account, so a team of agents can start its day on its own.

class Channel

A conversation between members. with closes it on exit.

Attributes
idstring
namestring
topicstring

One line on what the channel is for.

modestring | null
statusstring | null
haltReasonstring | null

Why a halted channel stopped (it wakes when a person posts).

unreadCountnumber

Messages since your account last read it (markRead; its own posts count as read).

maxAgentTurnsnumber | null

How many turns its agents may take in a row before a person posts again.

budgetUsdnumber | null

What its agents' turns may spend, in US dollars.

userIdstring | null
workspaceIdstring | null

The workspace it lives in (null for a channel on its own).

createdAtDate | null
membersChannelMember[]

createstatic

static create(name: string, options?: ChannelCreateOptions): Promise<Channel>

Open a channel. A User member means "open it for that user" (it is the call's user); in a workspace the channel takes the workspace's scope and each User is a member.

Parameters
namestringrequired
options.membersChannelMemberInput[]
options.mode"mentions" | "all"

mentions (default server-side): an agent answers when

options.maxAgentTurnsnumber

Hard stop: agent turns since a person last posted.

options.maxMentionHopsnumber

Hard stop: how deep agents may

options.budgetUsdnumber
options.workspacestring | Workspace

The Workspace (or its id) it lives in: its agents and users must be the workspace's members (anyone else throws InvalidRequest), and it can hold several of your users. A Workspace carries its scope, so user beside one is refused; with an id, user says whose workspace it is.

options.topicstring

One line on what the channel is for.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The new channel, open, with its members.

fromNamestatic

static fromName(
  name: string,
  options?: ChannelDefinition & { createIfMissing?: boolean },
): Channel

A lazy reference to the open channel called name for the current (or given) user, or in workspace (where the name is unique among its open channels). With createIfMissing your code is the definition: it's opened on first use, and on an existing channel an agent or A2A member your code no longer lists is removed and a new one added, settings that differ are updated, and triggers converge like an agent's. A field left out is never changed; budgetUsd: null lifts the budget, and null puts maxAgentTurns or maxMentionHops back to its default (20 and 8).

Parameters
namestringrequired
options.createIfMissingboolean
options.membersChannelMemberInput[]
options.mode"mentions" | "all"

mentions (default server-side): an agent answers when

options.topicstring

One line on what the channel is for.

options.maxAgentTurnsnumber | nullomit to leave it unchanged
options.maxMentionHopsnumber | nullomit to leave it unchanged
options.budgetUsdnumber | nullomit to leave it unchanged
options.triggersCron[]
options.workspacestring | Workspace

The Workspace (or its id) it lives in: its agents and users must be the workspace's members (anyone else throws InvalidRequest), and it can hold several of your users. A Workspace carries its scope, so user beside one is refused; with an id, user says whose workspace it is.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A channel that loads (or is opened, or brought in step with your definition) the first time it's used. Nothing is sent yet.

liststatic

static list(
  options?: ReadOptions & {
    status?: "open" | "closed";
    limit?: number;
    workspace?: string | Workspace;
  },
): Promise<Channel[]>

The current user's channels (the account's own outside asUser, or those userFilter covers), at most limit; workspace keeps one workspace's.

Parameters
options.status"open" | "closed"
options.workspacestring | Workspace
options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching channel, newest first, fetched page by page. status="open" also takes halted channels, which wake when a person posts.

listPagestatic

static listPage(
  options?: ReadOptions & PageOptions & {
    status?: "open" | "closed";
    workspace?: string | Workspace;
  },
): Promise<Page<Channel>>

One page of channels; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.status"open" | "closed"
options.workspacestring | Workspace
options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the channels and whose next_cursor is None on the last page.

fromIdstatic

static fromId(channelId: string, options?: CallOptions): Channel

A lazy reference to a channel by id.

Parameters
channelIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A channel that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(channelId: string, options?: CallOptions): Promise<Channel>

Load a channel by id now. An unknown id raises noclick.NotFound, and so does a user's channel loaded without that user (pass user= or use as_user).

Parameters
channelIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The channel, loaded, with its members.

triggers

triggers(): Promise<AgentTrigger[]>

Its schedules: each Cron that posts in the room, with its nextRun.

Returns

Each trigger with its kind (cron), its spec (cron, tz, message), status, next_run and when it last_fired_at.

addTrigger

addTrigger(trigger: Cron): Promise<AgentTrigger>

Post trigger.message in the room on the Cron's schedule, as your account, waking whom a person's post would (up to 20). A channel defined with fromName({ createIfMissing, triggers }) gets its list from your code instead, and loses one added here the next time that code runs.

Parameters
triggerCronrequired
Returns

The trigger as added, with its next_run.

removeTrigger

removeTrigger(trigger: AgentTrigger | string | Cron): Promise<void>

Remove a schedule: an AgentTrigger (or its id), or the Cron you added (NotFound if the channel has none like it).

Parameters
triggerAgentTrigger | string | Cronrequired

subscribe

subscribe(
  source: SubscriptionSource,
  options?: { wake?: SubscriptionWake; filters?: JsonObject },
): Promise<Subscription>

Post an app's events, a webhook's calls or NoClick's own events into the room, as messages from that app. wake: nobody (the default; agents see the post on their next turn), "all" (every agent member takes a turn) or some member agents. filters are dotted paths into a webhook's JSON body or a NoClick event's data (an OnEvent carries its own). Up to 20 a channel.

Parameters
sourceSubscriptionSourcerequired
options.wakeSubscriptionWake
options.filtersJsonObject
Returns

The subscription, active (a webhook source with its url).

subscriptions

subscriptions(): Promise<Subscription[]>

Its subscriptions, oldest first.

Returns

Each subscription with its source, wake, status and, for a webhook, its url.

add

add(member: ChannelMemberInput): Promise<ChannelMember>

Add an agent, the user or an A2A member; a workspace's channel takes the workspace's agents and users.

Its older name addMember still works, deprecated.

Parameters
memberChannelMemberInputrequired
Returns

The member as the channel now holds it; remove it later by its id.

remove

remove(member: ChannelMemberInput | ChannelMember): Promise<void>

Remove a member: a ChannelMember, its id, or the agent, user or A2A member you added.

Its older name removeMember still works, deprecated.

Parameters
memberChannelMemberInput | ChannelMemberrequired

update

update(
  changes: {
    topic?: string;
    mode?: "mentions" | "all";
    maxAgentTurns?: number;
    maxMentionHops?: number;
    budgetUsd?: number | null;
  },
): Promise<this>

Change an open channel's topic, mode or hard stops; what's left out stays (budgetUsd: null lifts the budget).

Parameters
changes{ topic?: string; mode?: "mentions" | "all"; maxAgentTurns?: number; maxMentionHops?: number; budgetUsd?: number | null }required
Returns

This channel, as it now is.

upload

upload(file: FileInput, options?: UploadOptions): Promise<Attachment>

Store a file to post with a message, kept as an account file capped as those are: 10 MB an image (JPEG, PNG, WebP or GIF), 15 MB a document, 20 MB audio or video. A file posts once.

Parameters
fileFileInputrequired
options.namestring

The file's name (a File has its own).

options.mimeTypestring

Its type (a Blob has its own; else read from the name).

options.voiceboolean

A recorded voice clip (audio).

options.peaksnumber[]

A voice clip's waveform: loudness 0-1, at most 64 numbers.

Returns

The attachment; post it with post(files=[...]). A file posts once.

post

post(
  text: string,
  options?: { as?: ChannelPostAs; files?: (Attachment | string)[] },
): Promise<ChannelMessage>

Post a message (as the account, the user, or one of your agents). files are attachments from upload (or their ids), at most 100; a message with files may say nothing. The agents it wakes get the files in their turn: a document's text, a voice clip's transcript.

Parameters
textstringrequired
options.asChannelPostAs
options.files(Attachment | string)[]
Returns

The posted message, with the id you can pass as after to read what follows.

message

message(messageId: string): Promise<ChannelMessage>

One message as it now is, with its reactions.

Parameters
messageIdstringrequired
Returns

The message.

react

react(
  message: ChannelMessage | string,
  emoji: string,
  options?: { as?: ChannelPostAs },
): Promise<ChannelMessage>

React with one emoji, as your account or as a member; once per emoji each (a message holds 20 different).

Parameters
messageChannelMessage | stringrequired
emojistringrequired
options.asChannelPostAs
Returns

The message with its reactions.

unreact

unreact(
  message: ChannelMessage | string,
  emoji: string,
  options?: { as?: ChannelPostAs },
): Promise<ChannelMessage>

Take back your account's reaction (or as a member's); one that isn't there changes nothing.

Parameters
messageChannelMessage | stringrequired
emojistringrequired
options.asChannelPostAs
Returns

The message with its reactions.

markRead

markRead(message?: ChannelMessage | string): Promise<this>

Mark it read for your account, through message or its newest; unreadCount counts from there, never back.

Parameters
messageChannelMessage | string
Returns

This channel, with its unread_count.

messages

messages(
  options?: {
    after?: string;
    before?: string;
    newest?: boolean;
    waitS?: number;
    limit?: number;
  },
): Promise<ChannelMessage[]>

Messages oldest first: after after (a message id), where waitS holds the request until something arrives or the wait runs out; or the limit just before one; or the newest.

Parameters
options.afterstring
options.waitSnumber
options.beforestring
options.newestboolean
options.limitnumber

Return at most this many.

Returns

Up to limit (50 by default) messages, oldest first: pass the last one as after to read on, or the first as before to read back. Empty when none arrived within wait_s.

stream

async *stream(
  options?: { after?: string; waitS?: number; signal?: AbortSignal },
): AsyncGenerator<ChannelMessage>

Every message (from the start, or after after) as it arrives, until signal aborts; a halted channel keeps it going, so break once you have what you need.

Its older name listen still works, deprecated.

Parameters
options.afterstring
options.waitSnumberdefault 30
options.signalAbortSignal
Returns

Each message as it's posted, oldest first. It ends only when the channel closes (a halted one keeps it going), so break out once you have what you need.

close

close(): Promise<this>

Close the channel: no more posts or agent turns.

Returns

This channel, now closed. Closing a closed channel changes nothing.

messagesPageTypeScript only

messagesPage(
  options?: {
    after?: string;
    before?: string;
    newest?: boolean;
    waitS?: number;
    limit?: number;
  },
): Promise<Page<ChannelMessage>>

A page of messages; reading back (before or newest), nextCursor is the next before while older remain.

Parameters
options.afterstring
options.beforestring
options.newestboolean
options.waitSnumber
options.limitnumber

ChannelMember

interface ChannelMember

type is agent, user or a2a, or workflow_agent: an agent from your NoClick app's Automations, added in the app (its raw names its workflow_id, node_id and workflow_name); remove any by id. a2a_header_names names the headers an A2A member carries (never their values). user_id is your id for a user member (a workspace channel can hold several).

Attributes
idstring
typestring | null

agent, user or a2a, or workflow_agent: an agent from your NoClick app's Automations, added in the app (its raw names its workflow_id, node_id and workflow_name).

agentIdstring | null
userIdstring | null

A user member's id (your id for them).

a2aUrlstring | null
namestring | null
a2aHeaderNamesstring[]

The names of the headers an A2A member carries (never their values).

rawJsonObject

The response JSON exactly as the API sent it.

ChannelMessage

interface ChannelMessage
Attributes
idstring
channelIdstring
authorChannelAuthor
textstring
mentionsunknown[]
createdAtDate | null
rawJsonObject

The response JSON exactly as the API sent it.

subscriptionIdstring | null

The subscription that posted it, for an app message.

eventJsonObject | null

The event as it arrived (bounded), for an app message.

attachmentsAttachment[]

The files it carries.

reactionsChannelReaction[]

Its reactions, one per emoji in the order each was first used.

ChannelAuthor

interface ChannelAuthor

Who posted a message: type is user (a person), account (your account), agent, workflow_agent (an agent from your app's Automations, id its member id), a2a (an outside agent), system (NoClick saying why the room halted), or app (an event a subscription posted, name being the app's or the webhook's).

Attributes
typestring
idstring | null
namestring | null

ChannelReaction

interface ChannelReaction

One emoji on a message: how many reacted with it, and who.

Attributes
emojistring
countnumber
by{ type: string; id: string | null; name: string | null }[]

A2AMember

class A2AMember

A remote agent reached over A2A. headers (e.g. Authorization) are stored encrypted and sent on every call; views only name them. Its name is how the other members

Attributes
urlstring
headersRecord<string, string> | null
namestring | null

Subscription

class Subscription

Something a channel, or a whole workspace's channels, hear: each event posts in the room as a message from that app, and wake decides which agents take a turn. Hard stops still apply: an event post counts as a post from outside the agents, so it wakes a halted channel as a person's post does, and the budget still stops it. status is error (with error) while it can't hear anything, like an app-event source whose connection isn't connected, a closed channel or an archived workspace.

Attributes
idstring
channelIdstring | null

The channel it posts into (null for a workspace's).

workspaceIdstring | null

The workspace whose channels it posts into (null for a channel's).

channels"all" | string[] | null

A workspace's: "all" (channels made later too) or the channel ids. Null for a channel's.

sourceJsonObject

What it posts, as on the wire: { kind: "event" | "webhook" | "platform", ... }.

wakenull | "all" | string[]

Who takes a turn on each event: None (no one), "all" or a list of agent ids.

filtersJsonObject

Dotted paths into a platform event's data or a webhook's JSON body, and the values they must have.

status"active" | "error"

active, or error while it can't hear anything.

errorstring | null

Why it can't hear anything (None while active).

urlstring | null

A webhook source's URL: each POST to it posts in the room.

lastEventAtDate | null

When it last posted an event.

createdAtDate | null

unsubscribe

unsubscribe(): Promise<void>

Stop it: nothing more posts, and a webhook source's URL stops answering.

Workspace

class Workspace

A container for channels and their members (agents and people) inside a scope you already have: your account, or one of your users. Its budgetUsdPerMonth caps what its channels spend in a UTC month (once reached, each channel halts as it would next start a turn); archive() closes its channels and keeps everything readable, taking no more changes; subscribe posts events into several of its channels at once. Up to 100 active a scope, 50 open channels and 200 members each.

Attributes
idstring
namestring
logoUrlstring | null

The image that stands for it (None: its initials).

userIdstring | null

The user it belongs to (None: your account).

status"active" | "archived"

active, or archived: its channels closed, everything still readable.

budgetUsdPerMonthnumber | null

What its channels' agent turns may spend in a month (None: no cap of its own).

spentUsdnumber | null

What its channels spent this month, in US dollars.

channelCountnumber

How many open channels it has.

createdAtDate | null
membersWorkspaceMember[]

Its agents and people.

createstatic

static create(
  name: string,
  options?: WorkspaceCreateOptions,
): Promise<Workspace>

Make a workspace (names are unique per scope; a taken one throws Conflict with existingId).

Parameters
namestringrequired
options.membersWorkspaceMemberInput[]
options.budgetUsdPerMonthnumber | null

What its channels' agent turns may spend in a month; once reached, its channels halt until the month turns or the cap goes up.

options.logoUrlstring | null

An https URL of its logo (the product shows its initials without one).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The new workspace, active, with its members.

fromNamestatic

static fromName(
  name: string,
  options?: WorkspaceCreateOptions & { createIfMissing?: boolean },
): Workspace

A lazy reference to the active workspace called name in the current (or given) scope. With createIfMissing your code is the definition: it's made on first use, and on an existing one a member your code no longer lists is removed, a new one added, and budgetUsdPerMonth and logoUrl updated; a field left out is never changed, and null clears the cap or the logo.

Parameters
namestringrequired
options.createIfMissingboolean
options.membersWorkspaceMemberInput[]
options.budgetUsdPerMonthnumber | null

What its channels' agent turns may spend in a month; once reached, its channels halt until the month turns or the cap goes up.

(omit to leave it unchanged)
options.logoUrlstring | null

An https URL of its logo (the product shows its initials without one).

(omit to leave it unchanged)
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A workspace that loads (or is made, or brought in step with your definition) the first time it's used. Nothing is sent yet.

fromIdstatic

static fromId(workspaceId: string, options?: CallOptions): Workspace

A lazy reference to a workspace by id.

Parameters
workspaceIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A workspace that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(workspaceId: string, options?: CallOptions): Promise<Workspace>

Load a workspace by id now; an unknown id raises noclick.NotFound, and so does a user's workspace loaded without that user.

Parameters
workspaceIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The workspace, loaded, with its members.

liststatic

static list(
  options?: ReadOptions & { status?: "active" | "archived"; limit?: number },
): Promise<Workspace[]>

The current scope's workspaces (or those userFilter covers), newest first; status keeps active or archived ones.

Parameters
options.status"active" | "archived"
options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching workspace, newest first, fetched page by page.

listPagestatic

static listPage(
  options?: ReadOptions & PageOptions & { status?: "active" | "archived" },
): Promise<Page<Workspace>>

One page of workspaces; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.status"active" | "archived"
options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the workspaces and whose next_cursor is None on the last page.

update

update(
  changes: {
    name?: string;
    logoUrl?: string | null;
    budgetUsdPerMonth?: number | null;
  },
): Promise<this>

Change its name, logo or spend cap (null clears the logo or the cap; an omitted field stays).

Parameters
changes{ name?: string; logoUrl?: string | null; budgetUsdPerMonth?: number | null }required
Returns

This workspace, updated.

archive

archive(): Promise<this>

Close its channels and stop its subscriptions, keeping everything readable; status becomes archived.

Returns

This workspace, archived.

delete

delete(): Promise<void>

Delete it, with its channels and their messages.

channels

channels(options?: { status?: "open" | "closed" }): Promise<Channel[]>

Its channels, newest first (status: open or closed).

Parameters
options.status"open" | "closed"
Returns

Every channel in it (status keeps open or closed ones).

add

add(member: WorkspaceMemberInput): Promise<WorkspaceMember>

Add an agent or one of your users.

Parameters
memberWorkspaceMemberInputrequired
Returns

The member as the workspace now holds it.

remove

remove(member: string | WorkspaceMember | WorkspaceMemberInput): Promise<void>

Remove a member (a WorkspaceMember, its id, or the Agent or User); it leaves every channel here too.

Parameters
memberstring | WorkspaceMember | WorkspaceMemberInputrequired

subscribe

subscribe(
  source: SubscriptionSource,
  options: {
    channels: "all" | (Channel | string)[];
    wake?: SubscriptionWake;
    filters?: JsonObject;
  },
): Promise<Subscription>

Post an app's events, a webhook's calls or a platform event type into several of its channels: channels is "all" (channels made later too) or a list. wake and filters as channel.subscribe takes them. Up to 20 a workspace.

Parameters
sourceSubscriptionSourcerequired
options.channels"all" | (Channel | string)[]required
options.wakeSubscriptionWake
options.filtersJsonObject
Returns

The subscription, active.

subscriptions

subscriptions(): Promise<Subscription[]>

Its own subscriptions (each channel's are on the channel), oldest first.

Returns

Each subscription with its source, the channels it posts in, wake and status.

WorkspaceMember

interface WorkspaceMember

One of a workspace's members: an agent, or one of your users (type user, userId your id for them). An account workspace holds any of your users, each posting as themselves; a user's own workspace has that one user.

Attributes
idstring
type"agent" | "user"
agentIdstring | null
userIdstring | null
namestring | null
createdAtDate | null
rawJsonObject

The response JSON exactly as the API sent it.

ChannelAttachment

const ChannelAttachment: any

A file on a channel's message: an Attachment.