Skip to main content

Overview

Ingestion is how you feed data into Synap’s memory system. Every conversation, document, email, or transcript you send through sdk.memories.create() enters the ingestion pipeline where it is categorized, chunked, entities are extracted and resolved, and the result is persisted across Synap’s vector and graph storage engines. Ingestion is asynchronous. When you call create(), Synap immediately returns an ingestion_id that you can use to poll the processing status. This design allows high-throughput workloads without blocking your application.

Creating a Memory

Use sdk.memories.create() to send a single document into the ingestion pipeline.
Key parameters for the example above:
  • document: the raw content to ingest (full transcript with speaker labels for conversations).
  • document_type: tells the pipeline which extraction and chunking strategy to apply. See Document Types below.
  • mode: the depth of extraction. See Ingest Modes below.
  • user_id / customer_id: control the memory scope. The effective scope is derived from the combination you pass plus the instance’s B2C vs B2B configuration; see Memory Scopes.
  • document_id: an optional idempotency key. Resubmitting the same document_id updates the existing memory instead of creating a duplicate.
The call returns immediately with an ingestion_id (status "queued") that you poll via sdk.memories.status().

Full parameter reference →

Every parameter, the complete response shape, and the errors raised by memories.create().

Document Types

The document_type parameter tells the ingestion pipeline which extraction and chunking strategies to apply.
For image and audio types, you provide the text content (description, transcript, or OCR output), not the raw binary file. Media processing and transcription should be handled upstream of Synap.

Ingest Modes

Synap offers two ingestion modes that trade off processing depth against throughput.

fast

Optimized for speed. Performs basic chunking, lightweight entity extraction, and vector embedding. Skips deep relationship mapping and advanced categorization.
  • Lower processing latency than long-range
  • Best for: high-throughput pipelines, real-time chat logging, non-critical data

long-range

Optimized for quality. Runs the full extraction pipeline including deep entity resolution, relationship mapping, preference detection, emotional analysis, and graph storage.
  • Higher processing latency than fast, in exchange for deeper extraction
  • Best for: conversations, documents where deep extraction matters, building long-term user profiles
Use long-range mode for conversations and documents where deep extraction matters. Use fast for high-throughput scenarios where speed is critical. You can always re-ingest a document in long-range mode later by resubmitting with the same document_id.
Ingestion mode values (fast / long-range) are distinct from retrieval mode values (fast / accurate). They control different stages of the pipeline and are not interchangeable; passing "accurate" to memories.create() or "long-range" to context.fetch() will be rejected.

Code Examples

Ingesting a Conversation

Ingesting a Document

Ingesting with User and Customer Scoping

When both user_id and customer_id are provided, the memory is accessible at both scopes. This is useful when a user’s conversation may contain information relevant to the broader organization.

Batch Ingestion

For bulk workloads, use sdk.memories.batch_create() to submit multiple documents in a single request.

The fail_fast Option

batch_create() takes a fail_fast flag (default False). With False, all documents are processed and invalid ones are rejected individually while valid ones proceed; with True, the entire batch aborts if any document fails validation and no documents are ingested.

Full parameter reference →

The CreateMemoryRequest fields, fail_fast semantics, and the BatchCreateResponse shape.

Recording Conversation Messages

sdk.memories.create() ingests a fully-formed document. For live agents that need to stream messages turn-by-turn (so compaction and get_context_for_prompt() always see the latest history), use sdk.conversation.record_message() instead.
A few things to get right for the example above:
  • conversation_id must be a valid UUID string (non-UUID values are rejected) and the same value should be reused across all turns of a single conversation.
  • role must be either "user" or "assistant".
  • content is subject to the per-message size limit listed in Performance & Limits.
The call returns a dict with message_id, conversation_id, session_id, and recorded_at.

Full parameter reference →

Every parameter, scope rules for customer_id, the response shape, and the errors raised.

Recording Messages in Batch

For backfills or buffered writes, record_messages_batch accepts a list of message dicts:
Returns a dict with total, succeeded, failed, and a per-message results[] list.
Recording messages is separate from ingesting a memory via memories.create(). Recorded messages are the input to compaction (compact() and get_context_for_prompt() need them). Memories created via memories.create() are the long-term, extracted, scope-aware knowledge layer. Most production agents do both: stream every turn via record_message() for live compaction, and periodically ingest the full conversation via memories.create() for long-term recall.

When one call is enough (cost & dedup)

“Do both” is the common pattern, not a requirement: the two calls serve different layers and carry different cost. Both consume credits; see Pricing & Credits for the model and sdk.credits.estimate() to size an operation before you run it.
  • record_message() is lightweight. It appends a turn to the conversation buffer that feeds compaction; it does not run the full extraction pipeline per call. Streaming every turn is the intended usage.
  • memories.create() is the heavier call. It runs chunking, entity extraction/resolution, and vector + graph persistence. Calling it on every turn, rather than periodically on a fuller transcript, is the main source of avoidable double-write cost.
Pick based on what each conversation actually needs:
  • Live compaction only (you only need a prompt-ready rolling summary, no long-term cross-conversation recall): record_message() alone is enough. Skip memories.create().
  • Long-term recall only (batch transcripts, documents, backfills where you never call compaction): memories.create() alone is enough. Skip record_message().
  • Both (live agents that also need durable, scope-aware memory): stream turns with record_message(), then ingest the assembled conversation with memories.create() periodically (e.g. at session end or every N turns) rather than per turn.
To keep the long-term layer from accumulating duplicates when you re-ingest a growing transcript, pass a stable document_id so repeat submissions update the existing memory instead of creating a new one. Extraction-level dedup (deduplicating overlapping facts/preferences across submissions) is handled by the ingestion pipeline and by smart-merge on update(); the document_id idempotency key is what prevents whole-document duplicates.

Checking Ingestion Status

Ingestion is asynchronous. Use sdk.memories.status() to poll the processing state of a submitted document.

Ingestion Statuses

The partial_success status typically occurs with large documents where some chunks process successfully while others encounter extraction errors. The successfully processed portions are still available for retrieval.

Updating Memories

Update an existing memory using sdk.memories.update(). This is useful when the source document has been edited or when you want to append new information.

Merge Strategies

Completely replaces the existing memory content with the new document. Previous extractions are discarded and re-extracted from the new content. Use when the document has been fully rewritten.
Adds the new content to the end of the existing memory. Previous extractions are preserved, and new extractions are generated only from the appended content. Use when adding new turns to a conversation.
Intelligently merges the new content with the existing memory. The pipeline detects overlapping sections, deduplicates extractions, and reconciles conflicting information by preferring the newer version. Use when the document has been partially edited.

Deleting Memories

Remove a memory and all its associated extractions permanently.
Deletion is permanent and irreversible. All extractions, entity associations, and graph relationships derived from this memory are removed. This operation cannot be undone.

Best Practices

Always prefix conversation turns with speaker labels (User:, Assistant:, or actual names). The ingestion pipeline uses these labels to correctly attribute preferences, facts, and intents to the right participant.
Use stable, deterministic identifiers for user_id and customer_id. These IDs form the basis of scoped retrieval. Inconsistent IDs fragment the user’s memory across multiple scopes.
When re-ingesting content that may have been submitted before (e.g., webhook retries), always provide a document_id. This prevents duplicate memories and ensures updates are applied cleanly.
When backfilling historical conversations or documents, set document_created_at to the original timestamp. This enables accurate temporal reasoning (“What did the user say last month?”).
Reserve long-range mode for content where deep understanding matters (user conversations, strategic documents). Use fast mode for high-volume, lower-priority data (automated logs, bulk imports).
For bulk ingestion (backfills, migrations), use batch_create() with fail_fast=False. This reduces HTTP overhead and allows the pipeline to optimize scheduling.

Next Steps

Context Fetch

Query the memories you have ingested for contextual retrieval.

Entity Resolution

Understand how entities are automatically resolved during ingestion.

Context Compaction

Compress long conversations to reduce token costs.

SDK Configuration

Configure SDK behavior, timeouts, and retry policies.