Appearance
Search API
Use the Search API to retrieve the most relevant messages, conversations, and memories from DialogueDB. Search is semantic first: you describe what you are looking for in natural language, then narrow the results with namespaces, tags, metadata, and dates.
http
POST /search
Authorization: Bearer <api-key>
Content-Type: application/jsonjson
{
"query": "customer cannot access account after password reset",
"object": "message",
"namespace": "tenant_acme",
"limit": 8
}json
{
"results": [
{
"object": "message",
"relevance": 0.86,
"item": {
"id": "msg_abc123",
"dialogueId": "dlg_789",
"role": "user",
"content": "I reset my password but still cannot sign in.",
"created": "2026-04-15T10:30:00.000Z",
"modified": "2026-04-15T10:30:00.000Z"
}
}
],
"request": {
"orderBy": "relevance",
"order": "desc",
"candidateOrderBy": "relevance"
}
}TIP
Search indexing is asynchronous. Newly created messages and memories are usually searchable within a few seconds.
Choose What To Search
The object field controls what Search returns. Pick the smallest object that gives your product the context it needs.
| Object | Returns | Best for |
|---|---|---|
message | Individual messages | Finding exact prior wording, answers, snippets, complaints, facts, and evidence |
dialogue | Conversation records | Finding whole conversations where a topic came up |
memory | Saved memory records | Retrieving durable user facts, preferences, profile details, and long-term context |
For most LLM features:
- Search
messagewhen the model needs source text to answer from. - Search
memorywhen the model needs remembered user or account context. - Search
dialoguewhen the UI should open or summarize related conversations. - Use
namespacewhenever you know the user, tenant, workspace, or organization. - Use filters when the user asks for a time period, product area, tier, status, channel, or other structured slice.
Using Search In LLM Tools
DialogueDB search works well as a tool for agents and copilots because the model can express intent in query and add constraints as structured fields.
A practical tool should expose:
ts
type DialogueDBSearchToolInput = {
query: string;
object: "message" | "dialogue" | "memory";
limit?: number;
namespace?: string;
tags?:
| string[]
| { $in?: string[]; $all?: string[]; $nin?: string[] };
metadata?: Record<string, unknown>;
filter?: {
created?: string | { gte?: string; gt?: string; lte?: string; lt?: string };
modified?: string | { gte?: string; gt?: string; lte?: string; lt?: string };
};
timezone?: string;
orderBy?: "relevance" | "created" | "modified";
order?: "asc" | "desc";
};Recommended model instructions:
- Use
messagefor exact source material. - Use
memoryfor durable facts, preferences, and user profile context. - Use
dialoguewhen the user asks for conversations, tickets, sessions, or threads. - Include
namespacewhen the current user, tenant, account, or workspace is known. - Prefer natural date phrases such as
"last 30 days"in bare-string date filters. - Use ISO timestamp ranges when exact boundaries matter.
- Do not treat
relevanceas a percentage. It only orders results within one response.
Build answer context from messages and memories
Use both message search and memory search when an assistant needs source evidence plus durable user context.
ts
async function buildAnswerContext(userQuery: string, namespace: string) {
const headers = {
Authorization: `Bearer ${process.env.DIALOGUEDB_API_KEY}`,
"Content-Type": "application/json"
};
const [messageResponse, memoryResponse] = await Promise.all([
fetch("https://api.dialoguedb.com/api/v1/search", {
method: "POST",
headers,
body: JSON.stringify({
query: userQuery,
object: "message",
namespace,
filter: { modified: "last 90 days" },
limit: 8
})
}),
fetch("https://api.dialoguedb.com/api/v1/search", {
method: "POST",
headers,
body: JSON.stringify({
query: userQuery,
object: "memory",
namespace,
limit: 5
})
})
]);
const [messageSearch, memorySearch] = await Promise.all([
messageResponse.json(),
memoryResponse.json()
]);
return {
messages: messageSearch.results.map((result) => result.item),
memories: memorySearch.results.map((result) => result.item)
};
}Tool call for an agent handling a support question
json
{
"query": "customer cannot access account after password reset",
"object": "message",
"namespace": "tenant_acme",
"tags": ["support"],
"filter": { "modified": "last 90 days" },
"limit": 8
}Tool call for remembered user preferences
json
{
"query": "notification preferences, timezone, communication style",
"object": "memory",
"namespace": "user_456",
"tags": { "$nin": ["expired"] },
"limit": 8
}Common Patterns
These examples are complete request bodies that you can send to /search.
Find exact prior messages
Use message when you want snippets, evidence, or prior wording.
json
{
"query": "I was charged twice for my order",
"object": "message",
"tags": ["support", "billing"],
"limit": 5
}Find related conversations
Use dialogue when you want the conversation records, not just individual lines of text.
json
{
"query": "account locked after password reset",
"object": "dialogue",
"namespace": "tenant_acme",
"metadata": {
"channel": { "$in": ["chat", "email"] },
"status": { "$ne": "archived" }
},
"filter": { "modified": "last 90 days" },
"limit": 10
}Retrieve durable user context
Use memory for profile facts, user preferences, decisions, constraints, or account context that should outlive one conversation.
json
{
"query": "preferences, constraints, profile, prior decisions",
"object": "memory",
"namespace": "user_456",
"limit": 10
}Search one tenant or workspace
Use namespace to keep retrieval inside the current user, tenant, account, organization, or workspace.
json
{
"query": "deployment failure",
"object": "dialogue",
"namespace": "tenant_acme",
"metadata": {
"environment": { "$nin": ["test", "staging"] }
},
"filter": { "created": "last 30 days" },
"orderBy": "modified",
"order": "desc",
"limit": 20
}Find recent high-priority issues
json
{
"query": "mobile crash",
"object": "dialogue",
"tags": { "$all": ["bug", "mobile"] },
"metadata": {
"priority": { "$gte": 5 },
"tier": { "$in": ["pro", "enterprise"] }
},
"filter": { "created": "last 30 days" },
"orderBy": "created",
"order": "desc",
"limit": 20
}Find product feedback from this quarter
json
{
"query": "confusing onboarding, missing feature, hard to use",
"object": "message",
"tags": ["feedback"],
"metadata": {
"product_area": { "$in": ["onboarding", "activation"] }
},
"filter": {
"created": {
"gte": "2026-04-01T00:00:00Z",
"lt": "2026-07-01T00:00:00Z"
}
},
"limit": 50
}Find renewal objections for customer success
json
{
"query": "renewal risk, pricing concern, missing security requirement",
"object": "dialogue",
"metadata": {
"stage": "renewal",
"tier": "enterprise"
},
"filter": { "modified": "last 6 months" },
"limit": 20
}Filters
Filters narrow semantic search to the part of your data that matters. Use them for isolation, permissions, product areas, time windows, status, customer tier, channel, and other structured attributes.
Namespace
namespace restricts search to one partition of your project. Common namespace choices are user IDs, tenant IDs, workspace IDs, organization IDs, or account IDs.
json
{
"query": "dietary restrictions",
"object": "memory",
"namespace": "user_456",
"limit": 5
}Tags
Tags are good for broad categories that can appear on many objects, such as support, billing, feedback, bug, sales, or expired.
ts
tags?:
| string[]
| { $in?: string[]; $all?: string[]; $nin?: string[] }| Form | Meaning |
|---|---|
["billing", "urgent"] | Has any listed tag. Same as { "$in": [...] }. |
{ "$in": ["billing", "urgent"] } | Has any listed tag. |
{ "$all": ["billing", "urgent"] } | Has every listed tag. |
{ "$nin": ["spam", "test"] } | Has none of the listed tags. |
Multiple tag operators are combined with AND.
Match any listed tag
json
{
"query": "payment issue",
"object": "dialogue",
"tags": ["billing", "payments", "refunds"],
"limit": 10
}Require every listed tag
json
{
"query": "payment issue",
"object": "dialogue",
"tags": { "$all": ["billing", "urgent"] },
"limit": 10
}Exclude tags
json
{
"query": "payment issue",
"object": "dialogue",
"tags": {
"$in": ["billing", "refunds"],
"$nin": ["test", "spam"]
},
"limit": 10
}WARNING
Tag arrays must contain at least one non-empty string. Unknown tag operators, empty arrays, and empty operator objects return 400 INVALID_PARAMETER.
Metadata
Metadata filters are best for structured fields you control, such as account tier, region, channel, priority, status, product area, customer ID, or plan.
ts
metadata?: Record<
string,
| string | number | boolean
| string[] | number[] | boolean[]
| {
$eq?: string | number | boolean;
$ne?: string | number | boolean;
$in?: string[] | number[] | boolean[];
$nin?: string[] | number[] | boolean[];
$gt?: number | string;
$gte?: number | string;
$lt?: number | string;
$lte?: number | string;
}
>;All metadata fields are combined with AND. Multiple operators on the same field are also combined with AND.
Match one metadata value
json
{
"query": "account upgrade",
"object": "dialogue",
"metadata": {
"tier": "enterprise"
},
"limit": 10
}Match any value in a list
json
{
"query": "mobile crash",
"object": "dialogue",
"metadata": {
"platform": { "$in": ["ios", "android"] }
},
"limit": 10
}Compare numeric metadata
json
{
"query": "crash",
"object": "dialogue",
"metadata": {
"priority": { "$gte": 5 }
},
"limit": 10
}Combine metadata fields
json
{
"query": "refund request",
"object": "dialogue",
"metadata": {
"tier": { "$in": ["pro", "enterprise"] },
"priority": { "$gte": 3 },
"status": { "$ne": "archived" }
},
"limit": 20
}WARNING
Metadata arrays in filters must be non-empty and homogeneous: all strings, all numbers, or all booleans. Unknown metadata operators and empty operator objects return 400 INVALID_PARAMETER.
Date Filters
Date filters use filter.created and filter.modified.
Use bare strings for natural date ranges:
json
{
"query": "billing",
"object": "dialogue",
"filter": { "created": "last 30 days" }
}Use range objects for exact boundaries and sub-day precision:
json
{
"query": "billing",
"object": "dialogue",
"filter": {
"created": {
"gte": "2025-03-01T00:00:00Z",
"lt": "2025-04-01T00:00:00Z"
}
}
}Half-open intervals (gte plus lt) are recommended because they avoid midnight-edge ambiguity.
Avoid natural phrases inside gte, gt, lte, or lt. Endpoints resolve to a single instant, not a range. Use bare-string form when you want DialogueDB to expand a phrase into a full range.
Accepted Date Phrases
| Phrase | Window |
|---|---|
"today", "yesterday", "tomorrow" | That one calendar day |
"Monday" | The most recent past Monday; works for any weekday name |
"2025" | The full calendar year, supported for years 1900 through 9999 |
"March 2025" | That full calendar month |
"2025-03-15" | That full calendar day |
"2025-03-15T10:30:00Z" | The calendar day containing that instant |
"this week" / "this month" / "this year" | The current calendar week (Monday-Sunday), month, or year |
"last week" / "last month" / "last year" | The previous calendar week, month, or year |
"next week" / "next month" / "next year" | The next calendar week, month, or year |
"last N days" / "past N days" | Rolling N-day window ending today |
"last N weeks" / "past N weeks" | Rolling 7N-day window ending today |
"last N months" / "past N months" | Same calendar day N months ago through today |
"last N years" / "past N years" | Same calendar day N years ago through today |
"N days ago", "N weeks ago", "N months ago", "N years ago" | A single calendar day exactly N units ago |
Rolling counts must be between 1 and 100000.
Calendar vs Rolling
"last week" and "last 7 days" are intentionally different:
"last week"means the previous calendar week, Monday through Sunday."last 7 days"means a rolling seven-day window ending today.
The same distinction applies to "last month" vs "last 30 days" and "last year" vs "last 365 days".
Timezone
The timezone field controls where day, week, month, and year boundaries fall. It accepts IANA timezone names such as "America/Chicago" and defaults to UTC.
When DialogueDB resolves a natural date phrase, the response includes the exact request.filter range that was used.
Use a user-local date phrase
json
{
"query": "support ticket",
"object": "dialogue",
"timezone": "America/Chicago",
"filter": { "created": "last 30 days" },
"limit": 10
}Example response excerpt:
json
{
"request": {
"orderBy": "relevance",
"order": "desc",
"candidateOrderBy": "relevance",
"filter": {
"created": {
"gte": "2026-04-28T05:00:00.000Z",
"lt": "2026-05-28T05:00:00.000Z"
}
}
}
}Search records from March 2025
json
{
"query": "migration issue",
"object": "message",
"filter": { "created": "March 2025" },
"limit": 20
}Search an exact ISO range
json
{
"query": "migration issue",
"object": "message",
"filter": {
"created": {
"gte": "2026-01-01T00:00:00Z",
"lt": "2026-02-01T00:00:00Z"
}
},
"limit": 20
}WARNING
Unsupported date inputs include made-up phrases, holiday names such as "Christmas" or "Black Friday", empty strings, years outside 1900-9999, rolling counts above 100000, and zero-count windows such as "last 0 days".
Ordering
Results are ordered by relevance by default.
json
{
"query": "billing dispute",
"object": "dialogue",
"orderBy": "created",
"order": "desc"
}Search always finds relevant results first. When you order by created or modified, DialogueDB takes the relevant results and reorders them by date. It does not scan your entire history newest-first looking for matches.
Use a date filter when the time window itself matters:
json
{
"query": "billing dispute",
"object": "dialogue",
"filter": { "created": "last 30 days" },
"orderBy": "created",
"order": "desc",
"limit": 20
}Response Fields
ts
{
results: Array<{
object: "message" | "dialogue" | "memory";
relevance: number;
item: Message | Dialogue | Memory;
matches?: Array<{
object: "message";
relevance: number;
item: Message;
}>;
}>;
request: {
orderBy: "relevance" | "created" | "modified";
order: "asc" | "desc";
candidateOrderBy: "relevance";
filter?: {
created?: { gte?: string; gt?: string; lte?: string; lt?: string };
modified?: { gte?: string; gt?: string; lte?: string; lt?: string };
};
};
}Each result wraps a matched object:
objectmatches the object type you requested.relevanceorders results within this response. Higher means more relevant. Do not treat it as a similarity percentage or compare it across different searches.itemis the fullMessage,Dialogue, orMemory.matchesappears on dialogue results when supporting message evidence is available.request.filterappears when DialogueDB resolved a natural date phrase, so you can verify the exact range used.
Request Reference
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural-language search text. |
object | "message" | "dialogue" | "memory" | Yes | Which kind of object to search. |
limit | number | No | Maximum results to return. Defaults to 50 for messages and 10 for dialogues or memories; maximum is plan-capped. |
namespace | string | No | Restrict search to one namespace. |
tags | string[] or operator object | No | Filter by tags. |
metadata | object | No | Filter by custom metadata fields. |
filter | object | No | Filter by created or modified time. |
timezone | string | No | IANA timezone used for natural date phrases, such as "America/Chicago". Defaults to UTC. |
orderBy | "relevance" | "created" | "modified" | No | Sort field. Defaults to "relevance". |
order | "asc" | "desc" | No | Sort direction. Defaults to "desc". |
Errors
Malformed requests return 400 INVALID_PARAMETER. Validation errors include a details array with the specific field, code, and message.
json
{
"error": {
"code": "INVALID_PARAMETER",
"type": "validation_error",
"details": [
{
"field": "filter.created",
"code": "INVALID_VALUE",
"message": "Could not parse \"purple monday\" as a date or date range"
}
]
}
}Common validation errors:
| Cause | Field | Detail code |
|---|---|---|
| Missing required field | query or object | MISSING_PARAMETER |
Invalid object | object | INVALID_TYPE |
Invalid orderBy or order | orderBy or order | INVALID_VALUE |
| Unknown filter key | filter.<key> | INVALID_KEY |
| Unparseable date phrase | filter.created or filter.modified | INVALID_VALUE |
| Unknown tag operator | tags.<op> | INVALID_KEY |
| Unknown metadata operator | metadata.<field>.<op> | INVALID_KEY |
| Empty operator object | tags or metadata.<field> | INVALID_VALUE |
Empty $in or $nin array | <field>.$in or <field>.$nin | INVALID_VALUE |
| Mixed-type array | <field>.$in or <field>.$nin | INVALID_TYPE |
Other responses:
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | API key does not have access to the requested project or namespace |
429 | Rate limited |
500 | Internal server error; retry after a brief delay |
Limits
Search results are capped by limit and by your plan. The endpoint does not currently paginate search results.
Relevant plan limits include:
- Maximum search results per response
- Tags per object
- Metadata size per object
- Metadata key length
- Metadata string-array element length
See the public limits endpoint at /api/public/meta for current plan values.

