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
const results = await db.searchMemories('support preferences');

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
});

Built with DialogueDB