Overview
Ingestion is how you feed data into Synap’s memory system. Every conversation, document, email, or transcript you send throughsdk.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
Usesdk.memories.create() to send a single document into the ingestion pipeline.
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 samedocument_idupdates the existing memory instead of creating a duplicate.
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
Thedocument_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
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 bothuser_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, usesdk.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.
conversation_idmust be a valid UUID string (non-UUID values are rejected) and the same value should be reused across all turns of a single conversation.rolemust be either"user"or"assistant".contentis subject to the per-message size limit listed in Performance & Limits.
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:
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 andsdk.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.
- Live compaction only (you only need a prompt-ready rolling summary, no long-term cross-conversation recall):
record_message()alone is enough. Skipmemories.create(). - Long-term recall only (batch transcripts, documents, backfills where you never call compaction):
memories.create()alone is enough. Skiprecord_message(). - Both (live agents that also need durable, scope-aware memory): stream turns with
record_message(), then ingest the assembled conversation withmemories.create()periodically (e.g. at session end or every N turns) rather than per turn.
Checking Ingestion Status
Ingestion is asynchronous. Usesdk.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 usingsdk.memories.update(). This is useful when the source document has been edited or when you want to append new information.
Merge Strategies
replace
replace
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.
append
append
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.
smart-merge
smart-merge
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.Best Practices
Include speaker labels in conversations
Include speaker labels in conversations
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.Set user_id and customer_id consistently
Set user_id and customer_id consistently
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.Use document_id for idempotency
Use document_id for idempotency
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.Provide document_created_at for historical data
Provide document_created_at for historical data
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?”).Choose the right mode for the workload
Choose the right mode for the workload
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).Batch when possible
Batch when possible
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.