Skip to content

State API ​

Manage temporary, dialogue-specific state data.

Overview ​

The State API provides a key-value store for dialogue-specific context and session data. Unlike memories (which persist across conversations and are searchable), state is designed for temporary, conversation-scoped data that changes frequently.

Key characteristics:

  • Scoped to individual dialogues
  • Merged with existing state on each update
  • Not searchable
  • Maximum 1MB uncompressed size
  • Can be updated even after dialogue is ended
  • Included automatically in dialogue GET responses

Common use cases:

  • Multi-step workflow progress tracking
  • Temporary session variables
  • Conversation context for your application logic
  • Shopping cart or form data during a conversation

Update Dialogue State ​

Create or update the state for a dialogue.

Endpoint ​

http
PUT /dialogue/{id}/state

Authentication ​

Bearer token (via Authorization header)

Path Parameters ​

ParameterTypeRequiredDescription
idstringYesDialogue identifier

Query Parameters ​

ParameterTypeRequiredDescription
namespacestringNoNamespace (required if the dialogue was created with one)

Request Body ​

Any JSON object representing your state data. The entire body becomes the state.

typescript
{
  [key: string]: any;  // Your custom key-value pairs
}

Response ​

The response body is the state

typescript
{
  [key: string]: any;
}

For example, if you set { "currentStep": "payment", "cartTotal": 299.99 }, the response is:

json
{
  "currentStep": "payment",
  "cartTotal": 299.99
}

Behavior ​

  • Creates state if it doesn't exist for the dialogue
  • Merges with existing state if it already exists - new keys are added, existing keys are updated, keys you don't mention are kept as-is
  • State data is compressed for efficient storage
  • Maximum 1MB uncompressed size
  • Can be updated even after dialogue status is "ended"
  • State is automatically included in GET /dialogue/{id} responses

Data Format ​

State accepts any valid JSON structure:

typescript
// Simple key-value
{
  "currentStep": "payment",
  "itemsInCart": 3
}

// Nested objects
{
  "user": {
    "name": "Jane",
    "preferences": {
      "theme": "dark"
    }
  },
  "session": {
    "started": "2025-01-15T10:00:00Z",
    "lastActive": "2025-01-15T10:30:00Z"
  }
}

// Arrays and mixed types
{
  "completedSteps": ["intro", "details", "review"],
  "score": 87,
  "isVerified": true
}

Use Cases ​

  • Conversation context: Track current topic, intent, or conversation stage
  • Multi-step flows: Store progress through wizards or forms
  • Session data: Temporary variables for the duration of the conversation
  • Application logic: Custom flags and state your app needs
  • Shopping carts: Items and totals during a purchase flow
  • Form data: Partially completed forms across multiple turns

Errors ​

StatusError CodeDescription
400MISSING_PARAMETERMissing required dialogue ID
400INVALID_INPUTInvalid JSON or exceeds 1MB size limit
401N/AUnauthorized - invalid or missing API key
404DIALOGUE_NOT_FOUNDDialogue does not exist
429RATE_LIMIT_EXCEEDEDToo many requests - retry with backoff
500INTERNAL_ERRORServer error - contact support with requestId

See Error Handling for complete error reference.

Examples ​

bash
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currentStep": "payment",
    "cartTotal": 299.99
  }'
typescript
const response = await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`,
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      currentTopic: 'billing',
      userIntent: 'cancel_subscription',
      requiresReview: true,
      supportTicketId: 'TKT-12345'
    })
  }
);

const state = await response.json();
console.log('State updated:', state);  // { currentTopic: 'billing', ... }
python
import requests

response = requests.put(
    f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}/state",
    headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"},
    json={
        "currentStep": "payment",
        "cartTotal": 299.99
    }
)

state = response.json()
print("State updated:", state)  # { "currentStep": "payment", ... }
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

// Option 1: Direct saveState call
await dialogue.saveState({

  shoppingCart: {
    items: [
      { id: 'prod_123', quantity: 2, price: 29.99 },
      { id: 'prod_456', quantity: 1, price: 49.99 }
    ],
    subtotal: 109.97,
    tax: 9.90,
    total: 119.87
  },
  checkoutStep: 'shipping'
});

// Option 2: Set state property and save
dialogue.state = { currentStep: 'payment', cartTotal: 299.99 };

await dialogue.save();

Retrieve Dialogue State ​

State is automatically included when retrieving a dialogue.

Endpoint ​

http
GET /dialogue/{id}

The response includes the state field containing your state data.

Response ​

typescript
{
  id: string;
  projectId: string;
  namespace?: string;
  // ... other dialogue fields
  state: Record<string, any>;  // Your state
}

Example ​

bash
curl https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123 \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY"

# Response includes state:
# {
#   "id": "dlg_abc123",
#   "state": {
#     "currentStep": "payment",
#     "cartTotal": 299.99
#   },
#   ...
# }
typescript
const response = await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}`,
  {
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY'
    }
  }
);

const dialogue = await response.json();

// Access state directly
console.log(dialogue.state.currentStep);  // "payment"
console.log(dialogue.state.cartTotal);    // 299.99
python
import requests

response = requests.get(
    f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}",
    headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
)

dialogue = response.json()

# Access state directly
print(dialogue["state"]["currentStep"])  # "payment"
print(dialogue["state"]["cartTotal"])    # 299.99
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

// Access state directly
console.log(dialogue.state.currentStep);  // "payment"
console.log(dialogue.state.cartTotal);    // 299.99

State Patterns ​

Multi-Step Workflow ​

Track progress through a multi-step process:

bash
# Step 1: Initialize workflow
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow": "account_setup",
    "currentStep": 1,
    "totalSteps": 4,
    "completed": [],
    "data": {}
  }'

# Step 2: Update as user progresses
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currentStep": 2,
    "completed": ["personal_info"],
    "data": {
      "email": "user@example.com",
      "name": "Jane Doe"
    }
  }'
typescript
// Step 1: Initialize workflow
await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`,
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workflow: 'account_setup',
      currentStep: 1,
      totalSteps: 4,
      completed: [],
      data: {}
    })
  }
);

// Step 2: Update as user progresses
await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`,
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      currentStep: 2,
      completed: ['personal_info'],
      data: {
        email: 'user@example.com',
        name: 'Jane Doe'
      }
    })
  }
);
python
import requests

headers = {"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
url = f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}/state"

# Step 1: Initialize workflow
requests.put(url, headers=headers, json={
    "workflow": "account_setup",
    "currentStep": 1,
    "totalSteps": 4,
    "completed": [],
    "data": {}
})

# Step 2: Update as user progresses
requests.put(url, headers=headers, json={
    "currentStep": 2,
    "completed": ["personal_info"],
    "data": {
        "email": "user@example.com",
        "name": "Jane Doe"
    }
})
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

// Step 1: Initialize workflow
await dialogue.saveState({
  workflow: 'account_setup',
  currentStep: 1,
  totalSteps: 4,
  completed: [],
  data: {}
});

// Step 2: Update as user progresses
await dialogue.saveState({
  currentStep: 2,
  completed: ['personal_info'],
  data: {
    email: 'user@example.com',
    name: 'Jane Doe'
  }
});

Conversation Context ​

Maintain conversational context:

bash
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currentTopic": "product_inquiry",
    "productId": "prod_123",
    "userSentiment": "interested",
    "questionsAsked": [
      "What are the specs?",
      "Is it in stock?"
    ],
    "lastIntent": "pricing_question"
  }'
typescript
await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`,
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      currentTopic: 'product_inquiry',
      productId: 'prod_123',
      userSentiment: 'interested',
      questionsAsked: [
        'What are the specs?',
        'Is it in stock?'
      ],
      lastIntent: 'pricing_question'
    })
  }
);
python
import requests

requests.put(
    f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}/state",
    headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"},
    json={
        "currentTopic": "product_inquiry",
        "productId": "prod_123",
        "userSentiment": "interested",
        "questionsAsked": [
            "What are the specs?",
            "Is it in stock?"
        ],
        "lastIntent": "pricing_question"
    }
)
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

await dialogue.saveState({
  currentTopic: 'product_inquiry',
  productId: 'prod_123',
  userSentiment: 'interested',
  questionsAsked: [
    'What are the specs?',
    'Is it in stock?'
  ],
  lastIntent: 'pricing_question'
});

Session Management ​

Track session-specific information:

bash
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session": {
      "id": "sess_xyz789",
      "startedAt": "2025-01-15T10:00:00Z",
      "lastActivity": "2025-01-15T10:30:00Z",
      "authenticated": true,
      "userId": "user_456"
    },
    "permissions": ["read", "write"],
    "features": ["premium_support", "priority_queue"]
  }'
typescript
await fetch(
  `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`,
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      session: {
        id: 'sess_xyz789',
        startedAt: '2025-01-15T10:00:00Z',
        lastActivity: '2025-01-15T10:30:00Z',
        authenticated: true,
        userId: 'user_456'
      },
      permissions: ['read', 'write'],
      features: ['premium_support', 'priority_queue']
    })
  }
);
python
import requests

requests.put(
    f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}/state",
    headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"},
    json={
        "session": {
            "id": "sess_xyz789",
            "startedAt": "2025-01-15T10:00:00Z",
            "lastActivity": "2025-01-15T10:30:00Z",
            "authenticated": True,
            "userId": "user_456"
        },
        "permissions": ["read", "write"],
        "features": ["premium_support", "priority_queue"]
    }
)
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

await dialogue.saveState({
  session: {
    id: 'sess_xyz789',
    startedAt: '2025-01-15T10:00:00Z',
    lastActivity: '2025-01-15T10:30:00Z',
    authenticated: true,
    userId: 'user_456'
  },
  permissions: ['read', 'write'],
  features: ['premium_support', 'priority_queue']
});

Form Data Collection ​

Store partially completed forms:

bash
# Initial form state
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "formType": "contact_request",
    "fields": { "name": null, "email": null, "company": null, "message": null },
    "validation": {},
    "complete": false
  }'

# Update as fields are filled
curl -X PUT https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/state \
  -H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "name": "Jane Doe",
      "email": "jane@example.com",
      "company": "Acme Corp",
      "message": null
    },
    "validation": { "name": true, "email": true, "company": true }
  }'
typescript
const headers = {
  'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
  'Content-Type': 'application/json'
};
const url = `https://api.dialoguedb.com/api/v1/dialogue/${dialogueId}/state`;

// Initial form state
await fetch(url, {
  method: 'PUT',
  headers,
  body: JSON.stringify({
    formType: 'contact_request',
    fields: { name: null, email: null, company: null, message: null },
    validation: {},
    complete: false
  })
});

// Update as fields are filled
await fetch(url, {
  method: 'PUT',
  headers,
  body: JSON.stringify({
    fields: {
      name: 'Jane Doe',
      email: 'jane@example.com',
      company: 'Acme Corp',
      message: null  // Still collecting
    },
    validation: { name: true, email: true, company: true }
  })
});
python
import requests

headers = {"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
url = f"https://api.dialoguedb.com/api/v1/dialogue/{dialogue_id}/state"

# Initial form state
requests.put(url, headers=headers, json={
    "formType": "contact_request",
    "fields": {"name": None, "email": None, "company": None, "message": None},
    "validation": {},
    "complete": False
})

# Update as fields are filled
requests.put(url, headers=headers, json={
    "fields": {
        "name": "Jane Doe",
        "email": "jane@example.com",
        "company": "Acme Corp",
        "message": None  # Still collecting
    },
    "validation": {"name": True, "email": True, "company": True}
})
typescript
import { DialogueDB } from 'dialogue-db';

const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
const dialogue = await db.getDialogue(dialogueId);

// Initial form state
await dialogue.saveState({
  formType: 'contact_request',
  fields: { name: null, email: null, company: null, message: null },
  validation: {},
  complete: false
});

// Update as fields are filled
await dialogue.saveState({
  fields: {
    name: 'Jane Doe',
    email: 'jane@example.com',
    company: 'Acme Corp',
    message: null  // Still collecting
  },
  validation: { name: true, email: true, company: true }
});

Best Practices ​

Merge Behavior ​

State updates are merged - new keys are added, existing keys are updated, and keys you don't include are kept as-is:

typescript
// Existing state: { step: 1, total: 100 }

await dialogue.saveState({
  step: 2  // Only updates 'step' - 'total' is preserved
});

// Resulting state: { step: 2, total: 100 }

This applies to nested objects as well:

typescript
// Existing state: { user: { name: "Jane", role: "admin" } }

await dialogue.saveState({
  user: { role: "viewer" }
});

// Resulting state: { user: { name: "Jane", role: "viewer" } }

Keep State Focused ​

State should be temporary and conversation-specific:

typescript
// Good: Conversation-specific context
{
  currentTopic: 'billing',
  pendingAction: 'cancel_subscription',
  requiresConfirmation: true
}

// Bad: Long-term user data (use Memory instead)
{
  userPreferences: { theme: 'dark' },  // Use Memory API
  accountHistory: [...],                // Use your own database
  pastPurchases: [...]                  // Use your own database
}

Size Management ​

Stay well under the 1MB limit:

typescript
// Monitor state size
const stateData = {
  // ... your state
};

const sizeInBytes = new Blob([JSON.stringify(stateData)]).size;
const sizeInKB = (sizeInBytes / 1024).toFixed(2);

console.log(`State size: ${sizeInKB} KB`);

if (sizeInBytes > 500000) { // 500KB warning threshold
  console.warn('State is getting large, consider optimization');
}

Clear State When Done ​

Clean up state when conversations end:

typescript
// Clear state after workflow completion
await dialogue.saveState({
  workflowComplete: true,
  clearedAt: new Date().toISOString()
});

// Or set to minimal state
await dialogue.saveState({});

State vs. Memory vs. Messages ​

Understanding when to use each storage type:

FeatureStateMemoryMessages
LifespanPer-dialogueIndefinitePer-dialogue
SearchNot searchableSearchableSearchable
UpdatesMerged on updateDelete/recreateImmutable
Size Limit1MBNo explicit limit1MB per message
Use CaseSession contextLong-term factsConversation turns
ScopeDialogue-specificGlobal/namespaceDialogue-specific

Use State when:

  • Tracking temporary conversation context
  • Multi-step workflow progress
  • Session-specific variables
  • Data that changes frequently during a conversation

Use Memory when:

  • Information should persist across dialogues
  • You need semantic search
  • Storing facts, preferences, or long-term knowledge

Use Messages when:

  • Recording actual conversation exchanges
  • Building context for LLM prompts
  • Need chronological dialogue history

Important Notes ​

State After Dialogue Ends ​

Unlike messages, state can be updated even after a dialogue is ended:

typescript
// End the dialogue
await dialogue.end();

// State can still be updated
await dialogue.saveState({
  finalStatus: 'completed',
  closedAt: new Date().toISOString()
});

State is Not Searchable ​

State is not searchable. If you need to find data by content, use Memory or Messages:

typescript
// Cannot search state

// Use Memory for searchable data
await db.createMemory({
  value: 'User prefers phone support',
  tags: ['preference', 'support']
});

// Search memories — results are wrapped in envelopes with relevance and item
const { results } = await db.searchMemories('support preferences');
const memories = results.map(r => r.item);

State is Per-Dialogue ​

Each dialogue has its own independent state. Use Memory with namespace for shared data:

typescript
// State is dialogue-specific
await dialogue1.saveState({ theme: 'dark' });
// dialogue2 doesn't have this state

// Use Memory with namespace for user-wide data
await db.createMemory({
  id: `user_${userId}_theme`,
  value: { theme: 'dark' },
  namespace: userId
});