channel docs

channel / reference

Schema

channelDomain declares one canonical message entity for every communication channel, four internal runtime entities, and two links into the events domain. Provider-specific records (a Resend email, a Twilio message) stay in app/provider domains and link back to channel_messages via externalId/raw.

channelDomain

@ekairos/channel/schema
import { channelDomain } from "@ekairos/channel/schema";

// domain("channel").includes(eventsDomain).withSchema({ entities, links, rooms })

The domain is named channel and composes eventsDomain, so it carries event_contexts and event_items with it — that is what the links below attach to.

channel_messages

The canonical message crossing any channel. This is the one public entity: your UI queries it, your endpoints write to it.

proptypedescription
channel *string — indexedChannel kind: web, email, whatsapp, or any custom kind.
direction *string — indexedinbound or outbound, relative to your system.
rolestring — optional, indexedConversational role: user, assistant, or system.
textstring — optionalPlain-text body of the message.
partsjson — optionalStructured message parts (rich content, attachments, tool output).
statusstring — optional, indexedDelivery status: pending, sending, sent, delivered, read, failed, or a provider-specific value.
externalIdstring — optional, indexedProvider-side id (Twilio SID, email message-id, ...).
participantstring — optional, indexedResolved identity of the counterpart (phone, email address, user id).
rawjson — optionalThe original provider payload, kept verbatim for audit and debugging.
createdAt *date — indexedCreation timestamp; the timeline sort key.
updatedAtdate — optionalLast update timestamp (e.g. on status transitions).

Internal runtime entities

The remaining four entities are internal runtime state for platform delivery (subscriptions, locks, caches, queues). They are owned by the channel domain so the whole channel stack persists on InstantDB — consumers never touch these entities directly.

channel_state
channel_state: i.entity({
  key: i.string().unique().indexed(),
  value: i.json().optional(),
  expiresAt: i.date().optional().indexed(),
  updatedAt: i.date(),
}),
proptypedescription
key *string — unique, indexedState entry key.
valuejson — optionalArbitrary state payload.
expiresAtdate — optional, indexedTTL for cache-style entries.
updatedAt *dateLast write timestamp.
channel_locks
channel_locks: i.entity({
  threadId: i.string().unique().indexed(),
  token: i.string(),
  expiresAt: i.date().indexed(),
}),
proptypedescription
threadId *string — unique, indexedOne lock per platform thread.
token *stringLock ownership token.
expiresAt *date — indexedLock expiry — stale locks are reclaimed.
channel_subscriptions
channel_subscriptions: i.entity({
  threadId: i.string().unique().indexed(),
  createdAt: i.date(),
}),
proptypedescription
threadId *string — unique, indexedSubscribed platform thread.
createdAt *dateWhen the subscription was created.
channel_queues
channel_queues: i.entity({
  threadId: i.string().indexed(),
  seq: i.number().indexed(),
  entry: i.json(),
  createdAt: i.date(),
}),
proptypedescription
threadId *string — indexedThread the queued entry belongs to.
seq *number — indexedOrdering sequence within the thread.
entry *jsonThe queued payload.
createdAt *dateEnqueue timestamp.
Treat channel_state, channel_locks, channel_subscriptions and channel_queues as private to the delivery runtime. Query and write channel_messages only.

Composition

channelDomain includes eventsDomain; the agent domain in turn includes channelDomain. Pushing the agent domain therefore gives you the whole stack — events, channel, and agent entities — in one InstantDB app.

instant.schema.ts
import { agentDomain } from "@ekairos/agent/schema";

export default agentDomain.toInstantSchema();

Only using channel without the agent layer? Push channelDomain.toInstantSchema() instead. Have your own app domain? Compose it:

instant.schema.ts (composed)
import { domain } from "@ekairos/domain";
import { agentDomain } from "@ekairos/agent/schema";
import { i } from "@instantdb/core";

const appDomain = domain("app")
  .includes(agentDomain)
  .withSchema({
    entities: {
      orders: i.entity({
        number: i.string().unique().indexed(),
        total: i.number(),
      }),
    },
    links: {},
    rooms: {},
  });

export default appDomain.toInstantSchema();
terminal
npx instant-cli@latest push schema

Next

database…