Skip to main content
Inkbox can derive concise memories from a contact’s email, SMS, iMessage, and call history. Every derived memory includes one or more citations to the source correspondence, and you can add or correct memories by hand. Contact list, create, update, and merge responses include memory_count, the number of memories currently in effect for that contact. The contact’s Memories permission controls fact text, counts, and latest-memory summaries while Profile is enabled. You can share profile details without memories, but not memories without Profile. Turning off either permission hides memories from that identity; it does not delete them. Hosted voice in YOLO mode retains organization-wide contact memory access. For an identity-scoped caller with memory access, citations owned by that identity include their source ID, locator, and resolver URL; citations owned by other identities redact those source details. Memory access does not grant access to another identity’s source conversations. Admin callers can inspect correspondence across the organization. See contact permissions.

List correspondence

Returns correspondence between one contact and one agent identity across supported channels. The SDK and CLI, starting with version 0.7.14, select all five channels when you omit their channel filter. Raw API requests retain the four-channel default shown above; request Slack explicitly, for example:
Slack correspondence contains retained messages authored by the contact’s verified saved Slack accounts, including multiple accounts across workspaces. It does not include every message in channels the contact belongs to, or attribute outgoing channel messages to that contact. Importing contacts does not import message history. The selected identity’s current access and contact rules still apply. Each Slack item has channel: "slack", direction: "inbound", a connection_id UUID, native Slack conversation_id, author workspace_id and user_id, message_ts, and nullable thread_ts. occurred_at is the Slack message time. text is null in metadata mode; text_truncated identifies shortened text in preview or full responses. Optional media reports an attachment count, and nullable sender_access classifies the message as direct or sponsored. Check the response’s channels summaries as well as items. A temporary Slack failure returns Slack status unavailable with no Slack items; other selected channels remain readable. This is not confirmation of empty Slack history. The Slack paging position does not advance. Continue with next_cursor when present, keeping the same filters. Otherwise retry the same request; items from available channels may repeat. Call items also include connections, using the same connection history fields as call reads: handoffs and conference additions, their destinations, outcomes, and lifecycle timestamps. Older responses may omit this field. Correspondence does not include a legacy forwardings list. Call transcript turns include a nullable phone_number in both abridged and full modes. Older responses can omit it; treat absence like null. It identifies the speaking human’s line or the agent’s dedicated line; shared local lines and unknown historical attribution return null. For older turns without a stored number, verified parent-call facts can supply the dedicated local line or the original remote line on a non-conference call. Unidentified conference speakers remain null. The number is separate from spoken text. Abridgment markers have no phone number.

Memory kinds

Every memory carries a kind saying what sort of thing it records: A contact holds up to 10 active memories of each kind. The three kind budgets are independent, so a contact already full on profile can still take a new preference or context memory. Memories Inkbox derives for you are also held to 30 active memories across the whole contact, and memories with kind: null count toward that total. Memories you add or edit yourself are held only to the 10-per-kind limit for the kind you choose, so a contact carrying memories recorded before kinds existed can end up above 30. A context memory carries an expires_at timestamp 30 days out. Each time the same situation comes up again in correspondence that timestamp moves forward, so a live project keeps its place while one that goes quiet drops out and frees its slot for something current. profile and preference memories report expires_at: null, as do memories you write or edit yourself, which are never rewritten or expired automatically whatever their kind. Once expires_at passes, an unlocked memory stops being returned, stops counting toward memory_count, and releases its context slot. A memory with locked_at remains active after that timestamp: it stays in the default list and count and continues using its slot. Expiry is not deletion: pass include_expired=true when listing to see expired memories.

List memories

Returns the contact’s memories in most-recently-updated order. Each memory contains:

Get a memory

Returns one memory with its citations under the same information-flow boundary described above. A memory ID stays readable once its deadline has passed, so this call returns expired memories without include_expired.

Add a memory

Records a memory you write yourself. This requires an admin-scoped API key or an authenticated Console user; an agent-scoped key cannot write memories.
The memory is created with origin: "user", no citations, and expires_at: null. Returns 409 when the contact already holds 10 active memories of that kind. Adding a memory never evicts an existing one; delete one first, then retry.

Edit a memory

Corrects the wording of a memory, moves it to a different kind, or both. An expired memory can be edited by ID. Same access as adding one: an admin-scoped API key or an authenticated Console user. Send at least one of the two. Neither accepts null, and an omitted field keeps its stored value.
Changing content drops the memory’s confidence and its citations, since that evidence supported the previous wording rather than yours. Changing kind alone leaves both in place. Any successful edit makes the memory origin: "user", clears expires_at, and revives it if it had expired. Moving a memory into context leaves expires_at as null, because a memory you curate stays until you remove it. Returns 409 when retyping or reviving the memory would put it into a kind that is already full.

Delete a memory

Deletes one active or expired memory. This requires an admin-scoped API key or an authenticated Console user. The response identifies the deleted fact and returns the contact’s remaining memory state:
latest_memory is null when no active memories remain.

Resolve a citation

Returns the source ID and locator after rechecking that the caller can still access the underlying correspondence. Returns 404 when the citation or its source is unavailable.

Merge duplicate contacts

Merges the contacts in losing_contact_ids into the contact named in the path. The survivor retains the combined identifiers, correspondence, and memories; losing contacts become merged records. This operation requires an admin-scoped API key or authenticated Console user.
field_sources is optional. It selects which merged contact supplies each scalar profile field. Each value must be the survivor ID or one of the losing_contact_ids. Allowed keys are preferred_name, name_prefix, given_name, middle_name, family_name, name_suffix, company_name, job_title, birthday, and notes. A merge holds the surviving contact to 10 active memories of each kind and 30 active memories in total, with kind: null memories counting toward the total. If the combined contacts would exceed a kind or total limit, the entire merge is rejected without changing any contact. The error names each overflowing kind or total: delete a memory from each named kind, or any active memory for total, then retry. The response is the surviving contact and includes its current memory_count and latest_memory.