> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Maximem Synap is a managed memory layer for AI agents: it ingests conversations and documents, extracts structured memory, and returns scoped context to the agent at retrieval time.
> The Python and JavaScript/TypeScript SDKs are the supported way to use Synap. Write integration code with SDK calls, not raw HTTP requests.
> Start with the Quickstart: https://docs.maximem.ai/getting-started/quickstart.md. Every SDK method is documented in the SDK reference: https://docs.maximem.ai/sdk-reference/overview.md.

# Types and enums

> The values several SDK methods share: every allowed value, its default, the JavaScript spelling, and whether a bad value is caught before the request is sent.

Several SDK methods take the same option values or return the same statuses. This page lists each set once, so the method pages can link here instead of repeating it.

## How to read this page

* **Values are identical in Python and JavaScript.** Only option names can differ.
* **JavaScript option names.** Most JavaScript methods take an options object that accepts a multi-word option in snake\_case or camelCase, so `scope_path` and `scopePath` both work. The cross-scope `sdk.fetch()` reads snake\_case names only. The tables use snake\_case, which works everywhere.
* **Where a bad value is caught.** "SDK" means the call fails before any request is sent. "Server" means the request goes out and the server refuses it; both SDKs raise a 400 or 422 answer as `InvalidInputError`. "Not checked" means nothing refuses the value, and the section says what happens instead.
* **Python errors.** Most refused values raise `InvalidInputError`. A few Python checks raise `ValueError`, or pydantic's `ValidationError` (a `ValueError` subclass), which an `except SynapError` block does not catch. The sections name them. See [Errors](/sdk-reference/errors) for the full hierarchy.

Both SDKs export most of these sets as constants, which you can use to validate input or build a menu:

```python Python theme={null}
from maximem_synap import DocumentType
from maximem_synap.models.context import MEMORY_TYPES, RESPONSE_SHAPES

print([t.value for t in DocumentType])  # ['ai-chat-conversation', 'document', ...]
print(MEMORY_TYPES)     # ('facts', 'preferences', 'episodes', 'emotions', 'temporal_events')
print(RESPONSE_SHAPES)  # ('by_type', 'ranked')
```

```typescript TypeScript theme={null}
import { DOCUMENT_TYPES, MEMORY_TYPES, RESPONSE_SHAPES } from '@maximem/synap-js-sdk';
import type { DocumentType } from '@maximem/synap-js-sdk';

const docType: DocumentType = 'meeting-transcript'; // a misspelled value fails to compile
console.log(docType, DOCUMENT_TYPES, MEMORY_TYPES, RESPONSE_SHAPES);
```

## Document type

`document_type` tells the server what kind of content it is reading, and extraction depends on it: conversational text sent as `document` yields less than the same text sent as `ai-chat-conversation`. Label each write for what it is.

Used by [`memories.create`](/sdk-reference/memories/create), [`memories.batch_create`](/sdk-reference/memories/batch-create) (on each document), [`memories.create_from_file`](/sdk-reference/memories/create-from-file) and [`memories.update`](/sdk-reference/memories/update).

| Value | Content |
| - | - |
| `ai-chat-conversation` | A conversation between a person and an AI agent. The default for `create` and `batch_create`. In Python the enum member is `DocumentType.CONVERSATION`. |
| `document` | A general document. The server also uses it for `create_from_file` when you send no type. |
| `email` | An email or an email thread. |
| `pdf` | Text from a PDF. |
| `image` | Content taken from an image. |
| `audio` | Content taken from audio. |
| `meeting-transcript` | A meeting transcript. |

| | Python | JavaScript |
| - | - | - |
| Option name | `document_type` | `document_type` or `documentType` |
| `create`, `batch_create` | SDK. `create` raises `ValueError`; building a `CreateMemoryRequest` for `batch_create` raises `ValidationError`. | SDK: `InvalidInputError`. |
| `create_from_file` | Not checked. The server treats a value it does not recognize as `document`. | Same as Python. |
| `update` | SDK: `ValueError`. | Not checked. |
| Constants | `DocumentType` | `DOCUMENT_TYPES`, `DEFAULT_DOCUMENT_TYPE`, type `DocumentType` |

## Ingestion mode

`mode` on a write. Used by [`memories.create`](/sdk-reference/memories/create), [`memories.batch_create`](/sdk-reference/memories/batch-create) (on each document) and [`memories.create_from_file`](/sdk-reference/memories/create-from-file).

| Value | |
| - | - |
| `long-range` | The default in both SDKs and on the server. |
| `fast` | The other accepted value. |

The server accepts either value, and in the current release both run the same ingestion pipeline, so the choice does not change what is extracted.

| | Python | JavaScript |
| - | - | - |
| Option name | `mode` | `mode` |
| `create`, `batch_create` | SDK. `create` raises `ValueError`; a `CreateMemoryRequest` raises `ValidationError`. | SDK: `InvalidInputError`. |
| `create_from_file` | Not checked by the SDK or the server. | Same as Python. |
| Constants | `IngestMode` | `INGEST_MODES`, `DEFAULT_INGEST_MODE`, type `IngestMode` |

## Ingestion status

The `status` of an ingestion job. The write methods return it on their result, and you poll it with [`memories.status`](/sdk-reference/memories/status) and [`memories.wait_for_completion`](/sdk-reference/memories/wait-for-completion). [`conversation.ingest_transcript`](/sdk-reference/conversation/ingest-transcript) returns its own `status` (`queued` or `duplicate`) together with an `ingestion_id` that you poll with these values.

| Value | Meaning | Final |
| - | - | - |
| `queued` | Accepted and waiting for a worker. Every new job starts here. | No |
| `processing` | A worker has picked it up. | No |
| `completed` | Finished. `memory_ids` lists the memories it stored. | Yes |
| `failed` | Stopped; `error_message` says why. In `batch_create`, a document the server refuses comes back as `failed` at once. | Yes |
| `partial_success` | Finished, but a write to one of the memory stores failed, so some of what it extracted may be missing. | Yes |

`wait_for_completion` polls `status` for you, and the two SDKs stop at different points:

* **Python** returns at `completed`, `failed` or `partial_success`. If none arrives within `timeout_seconds` (default 300, polling every `poll_interval_seconds`, default 2), it raises the built-in `TimeoutError`.
* **JavaScript** returns at `completed` or `failed`. It does not stop at `partial_success`, so a job that ends that way is polled until the timeout. At the timeout it returns the last status instead of throwing, so check `status` on what it returns.

Constants: Python `IngestStatus`. JavaScript has none; `status` is a string.

## Retrieval mode and precision

Two independent settings on every context fetch: [`sdk.fetch`](/sdk-reference/context/fetch), [`user.context.fetch`](/sdk-reference/context/user-fetch), [`customer.context.fetch`](/sdk-reference/context/customer-fetch), [`client.context.fetch`](/sdk-reference/context/client-fetch) and [`conversation.context.fetch`](/sdk-reference/conversation-context/fetch). The tool from [`as_tool`](/sdk-reference/lifecycle/as-tool) lets the model pick them from the same values. Both are ignored in [conversation-summary mode](#context-mode). For when to use which, see [Retrieval modes](/concepts/retrieval-modes).

`mode`:

| Value | Meaning |
| - | - |
| `fast` | Default. Searches your queries directly, without a language model rewriting them. |
| `accurate` | A language model first writes sub-queries from your first search query; each one is searched and the results are merged. Slower than `fast`. |

`precision_level`:

| Value | Meaning |
| - | - |
| `high` | Default. Runs a relevance-refinement pass over the results before returning them. |
| `medium` | Skips that pass. The same memories are searched; results come back faster and less precisely filtered. |

| | Python | JavaScript |
| - | - | - |
| Option names | `mode`, `precision_level` | `mode`; `precision_level` or `precisionLevel` |
| Checked by | SDK: `InvalidInputError` | SDK: `InvalidInputError` |
| Constants | `RetrievalMode` in `maximem_synap.models.enums` (`mode` only) | None |

> [!WARNING]
>
> JavaScript SDK 0.5.9 and earlier do not check `mode`, and the server runs `accurate` for any value other than `fast`. On those versions a typo such as `"Fast"` switches to the slower mode without an error. A bad `precision_level` is still refused by the server.

## Memory types

The five kinds of memory Synap extracts. The same names are used for the `types` filter on fetches, for the lists in a fetch response, for `memory_type` on [`memories.get`](/sdk-reference/memories/get), and for the `context_types` hint on [`instance.send_message`](/sdk-reference/instance/send-message).

| Value | Holds | Python item class |
| - | - | - |
| `facts` | A piece of factual information about someone or something. | `Fact` |
| `preferences` | A preference or a behavioral pattern. | `Preference` |
| `episodes` | A memorable event or interaction. | `Episode` |
| `emotions` | A detected emotional state. | `Emotion` |
| `temporal_events` | An event or fact with explicit time boundaries. | `TemporalEvent` |

A ranked response adds one more category, `excerpts`: quotes from source documents rather than extracted memories. See [Response shape](#response-shape).

**The `types` filter** on `sdk.fetch` and the four scoped fetches narrows a fetch to some of the five. Leave it out to get all five; the SDKs then send `["all"]`, and any list that contains `"all"` means all five.

| | Python | JavaScript |
| - | - | - |
| Option name | `types` | `types` |
| Checked by | Not checked. | Not checked, except that it must be an array (`InvalidInputError`). |
| Unknown name | The server does not refuse it. It filters on the name, so a misspelled type returns fewer items, or none, without an error. | Same as Python. |
| Constants | `MEMORY_TYPES` in `maximem_synap.models.context` | `MEMORY_TYPES`, `ITEM_COLLECTIONS`, type `ItemCollection` |

> [!WARNING]
>
> Python's exported `ContextType` enum spells the last type `temporal` (`ContextType.TEMPORAL`). The server does not know that name, so filtering with it returns no temporal events. Use the string `"temporal_events"` or `MEMORY_TYPES`.

## Response shape

`response_shape` sets how a fetch returns its items. Used by [`sdk.fetch`](/sdk-reference/context/fetch) and the four scoped fetches.

| Value | What you get |
| - | - |
| `by_type` | Default. Five lists, one per memory type. Quotes from source documents are filed under `facts`. |
| `ranked` | The five lists, plus `items`: every item once, best first across types. Each item carries its type in `category`, its place in `rank` (from 1) and the score it was ranked by (`rank_score` in Python, `metadata.rank_score` in JavaScript). Quotes from source documents get the category `excerpts` and are listed in `excerpts` instead of `facts`. From `sdk.fetch`, `formatted_context` becomes one numbered list in rank order. |

| | Python | JavaScript |
| - | - | - |
| Option name | `response_shape` | `response_shape` or `responseShape` |
| Checked by | SDK: `InvalidInputError` | SDK: `InvalidInputError` |
| Constants | `RESPONSE_SHAPES` in `maximem_synap.models.context` | `RESPONSE_SHAPES`, `EXCERPT_CATEGORY`, type `ResponseShape` |

## Context mode

`context_mode` switches a user-scope fetch between normal retrieval and a summary for the start of a call or session. Used by [`user.context.fetch`](/sdk-reference/context/user-fetch) and [`sdk.fetch`](/sdk-reference/context/fetch). `sdk.fetch` passes it only to its user-scope part, so it needs `user_id`.

| Value | What you get |
| - | - |
| `in-conversation` | Default. Normal retrieval: the memory-type lists. |
| `conversation-summary` | A caller profile in `profile` and summaries of previous conversations in `conversations`; the memory lists are empty. `search_query`, `mode`, `precision_level` and `response_shape` are ignored. On a B2B instance, send `customer_id` too. |

Two options apply in summary mode only:

| Option | Default | Meaning |
| - | - | - |
| `include_profile` | `True` (`true` in JavaScript) | Include the caller profile. |
| `last_n_conversations` | `1` | How many previous conversations to summarize, from 0 to 20. |

| | Python | JavaScript |
| - | - | - |
| Option names | `context_mode`, `include_profile`, `last_n_conversations` | Also `contextMode`, `includeProfile`, `lastNConversations` |
| Checked by | SDK: `InvalidInputError` for an unknown mode, or a count outside 0 to 20 | Same as Python. |

The server refuses summary mode on the customer, client and conversation fetches, which is why the SDKs send it only with a user-scope fetch.

## Fetch scopes

`scopes` on [`sdk.fetch`](/sdk-reference/context/fetch) limits which scopes are queried.

| Value | Queried when |
| - | - |
| `conversation` | You pass `conversation_id`. |
| `user` | You pass `user_id`. |
| `customer` | You pass `customer_id`. |
| `client` | You list it. Client scope is memory shared across your whole account and needs no id, so `sdk.fetch` never queries it unless you ask. |

Left out, `scopes` means every scope you passed an id for. A listed scope whose id you did not pass is skipped. An unknown name is ignored without an error in both SDKs, so check the spelling. The response's `scopes_queried` and `scope_map` use the same names.

Constants: Python `ContextScope`. JavaScript type `Scope`.

## Scope paths

On an account whose [scope ladder](/concepts/scope-ladder) has a level between customer and user, `customer_id` and `user_id` cannot say which level a request belongs to; a scope path names it. On the default three levels you do not need one.

| Option | Methods |
| - | - |
| `scope` | [`memories.create`](/sdk-reference/memories/create), [`memories.batch_create`](/sdk-reference/memories/batch-create) (on each document), `memories.forget` |
| `scope_path` | [`conversation.record_message`](/sdk-reference/conversation/record-message), [`conversation.record_messages_batch`](/sdk-reference/conversation/record-messages-batch) (on each message), [`conversation.ingest_transcript`](/sdk-reference/conversation/ingest-transcript), and the four scoped fetches: [`user`](/sdk-reference/context/user-fetch), [`customer`](/sdk-reference/context/customer-fetch), [`client`](/sdk-reference/context/client-fetch) and [`conversation`](/sdk-reference/conversation-context/fetch) |

Both names carry the same thing and reach the server as `scope`. The shape is a flat map from level key to your id, both strings: `{"customer": "acme", "team": "payments", "user": "dana"}`. Neither SDK checks the shape. The server enforces these rules and refuses a path that breaks one (400, raised as `InvalidInputError`):

* Use the level keys from your ladder. Leave out the top level; it is your account and is implied.
* Name every level from the first one below your account down to the level you mean. A path with a gap is refused, and the error names the missing level.
* A key that is not a level on your ladder is refused.
* Key order does not matter.
* If nested scoping is not enabled for your instance, a path is refused rather than ignored, because ignoring it would widen the request.
* For a conversation, sending the path once is enough: the server fills in a missing path and never overwrites one.

`sdk.fetch` takes no path in either SDK. Python's `create_from_file` has no `scope` option, and although the JavaScript type definitions accept one there, the SDK does not send it. JavaScript SDK 0.5.9 and earlier send `scope_path` on `user.context.fetch` only and drop it on the other three fetches. For worked examples, see [Sending a scope path](/concepts/scope-ladder#sending-a-scope-path).

## Message roles

| Where | Values | Checked by |
| - | - | - |
| `role` on [`record_message`](/sdk-reference/conversation/record-message) and [`record_messages_batch`](/sdk-reference/conversation/record-messages-batch) | `user`, `assistant` | Python SDK: `ValueError`. JavaScript: server, `InvalidInputError`. |
| `role` on each [`ingest_transcript`](/sdk-reference/conversation/ingest-transcript) turn | `user`, `assistant` | Python SDK: `ValidationError` when the `TranscriptTurn` is built. JavaScript: server, `InvalidInputError`. |
| `role` on [`send_message`](/sdk-reference/instance/send-message) | Default `user` | Not checked. |

On the stream, the helper methods set the role for you: [`record_tool_call`](/sdk-reference/instance/record-tool-call) sends `assistant`, [`record_tool_result`](/sdk-reference/instance/record-tool-result) sends `tool`, and [`record_thinking`](/sdk-reference/instance/record-thinking) sends none. Use them rather than setting `role` yourself for those events.

If you pass `ingest_transcript` a plain string, the server splits it at lines that start with a speaker label and a colon: `user`, `assistant`, `human`, `ai`, `system` or `bot`, in any case. `user` and `human` become user turns; every other label becomes an assistant turn. Text before the first label is kept as a user turn, and text with no labels becomes one user turn.

## Stream event types

`event_type` on [`instance.send_message`](/sdk-reference/instance/send-message) says what a stream event is. The stream must be open ([`instance.listen`](/sdk-reference/instance/listen)), or the call raises `ListeningNotActiveError`.

| Value | Use it for |
| - | - |
| `user_message` | Default. A message from the user. |
| `assistant_message` | Your agent's reply. |
| `tool_call` | A tool your agent is about to call. Prefer [`record_tool_call`](/sdk-reference/instance/record-tool-call), which also sets the role. |
| `tool_result` | What a tool returned. Prefer [`record_tool_result`](/sdk-reference/instance/record-tool-result). |
| `agent_thinking` | A reasoning step between the user's message and the reply. Prefer [`record_thinking`](/sdk-reference/instance/record-thinking). |
| `context_request` | Your agent is about to fetch context. Put the planned queries in `search_queries` and the memory types in `context_types`, as hints. |
| `context_fetch` | A fetch that already happened. The Python SDK sends one itself after each scoped fetch while the stream is open. |
| `session_start` | A session began. |
| `session_end` | A session ended. To close a conversation's session, use [`instance.end_session`](/sdk-reference/instance/end-session). |

Both SDKs refuse any other value before sending: Python raises `ValueError`, JavaScript raises `SynapError`. Neither exports the list from the package root; Python keeps it in `maximem_synap.sdk.KNOWN_EVENT_TYPES`.

## Compaction values

### Strategy

`strategy` on [`conversation.context.compact`](/sdk-reference/conversation-context/compact) names the compaction strategy for one run. Leave it out to use the strategy configured for your instance. The server knows four names: `aggressive`, `balanced`, `conservative` and `adaptive`. The strategy that ran comes back as `strategy_used` on [`get_compacted`](/sdk-reference/conversation-context/get-compacted), and Python also parses it into `level_applied`.

`compaction_level` is an older name for the same option; `strategy` wins when you pass both. The SDK lists for it (Python `CompactionLevel`, JavaScript `COMPACTION_LEVELS`) also include `low`, `medium` and `high`, which are not server strategy names.

Neither SDK checks the value, and the server does not refuse an unknown one: it logs it and keeps the configured strategy. A typo, or `low`, `medium` or `high`, changes nothing and raises no error.

### Compaction status

`status` from [`get_compaction_status`](/sdk-reference/conversation-context/get-compaction-status):

| Value | Meaning |
| - | - |
| `not_started` | No compacted version exists for the conversation, and no recent attempt failed. |
| `in_progress` | A compaction is running. `compact()` also returns this status. |
| `completed` | A compacted version exists. `compaction_id`, `completed_at` and `latest_version` describe the newest one. |
| `failed` | The last attempt failed and no compacted version exists. `error_message` says why. |

Python can answer `completed` without a request when a compaction update for the conversation has already arrived on the listen stream.

### Layout: `format` and `style`

`format` on [`get_compacted`](/sdk-reference/conversation-context/get-compacted) and `style` on [`get_context_for_prompt`](/sdk-reference/conversation-context/get-context-for-prompt) take the same three values:

| Value | Layout |
| - | - |
| `structured` | Default. Sections under headings. |
| `narrative` | Prose paragraphs. |
| `bullet_points` | Short bullet lists. |

Neither SDK checks the value, and the server does not validate it up front, so stay with these three. The Python docstring for `get_compacted` mentions `injection`; the server has no such format.

## Forget mode and status

`memories.forget` finds memories that match a description in the user's own words (3 to 500 characters) and removes them.

`mode`:

| Value | Meaning |
| - | - |
| `preview` | Default. Finds the matches and files a pending deletion request that a person approves in the dashboard under Deletion requests. Deletes nothing; `candidates` lists the matches. |
| `direct` | Finds and soft-deletes in one call, with no review. Repeating it is harmless, but each call is a new request. |

`status` on the result:

| Value | Meaning |
| - | - |
| `nothing_matches` | Nothing matched the description. |
| `preview` | A deletion request was filed for a person to review. |
| `deleted` | The matches were deleted. Only this status means the text is gone. |
| `partial` | The memories are hidden, but a store named in `still_present_in` may still hold the text. Do not tell the user it was removed. |

The result also carries `failed_ids` (memories that could not be deleted) and `may_be_incomplete` (true when a search limit stopped the matching early). Each candidate's `store` says where the matched text lives: `memory` for the memory itself, or `chunk`, `sentence`, `entity`, `triple`, `profile` or `candidate` for a copy kept elsewhere.

| | Python | JavaScript |
| - | - | - |
| Checked by | SDK: `InvalidInputError` for an unknown mode, or a description outside 3 to 500 characters | Same as Python. |
| Scope | The request must resolve to one user: send `user_id`, plus `customer_id` on B2B. Otherwise the server refuses it (400, `InvalidInputError`). | Same as Python. |
| Constants | `ForgetMode`, `ForgetStatus` | `FORGET_MODES`, types `ForgetMode` and `ForgetStatus` |

## Tool scope and style

[`as_tool`](/sdk-reference/lifecycle/as-tool) returns a tool definition that fetches Synap context when the model calls it. The ids you pass are fixed inside the tool, so the model cannot choose whose memory to read.

`scope` (case-insensitive):

| Value | Fetches with |
| - | - |
| `user` | Default. `user.context.fetch`. Requires `user_id`. |
| `customer` | `customer.context.fetch`. Requires `customer_id`. |
| `client` | `client.context.fetch`. |
| `conversation` | `conversation.context.fetch`. Pass `user_id` as well; without it the SDK warns. If you pass no `conversation_id`, the model supplies one on each call. |
| `unified` | `sdk.fetch`, across every scope you passed an id for. |

`style`:

| Value | Shape |
| - | - |
| `openai` | Default. `{"type": "function", "function": {...}}` |
| `anthropic` | `{"name": ..., "description": ..., "input_schema": ...}` |

Both shapes carry a `handler` that runs the fetch, and the default tool name is `synap_fetch_<scope>_context`. Both SDKs raise `InvalidInputError` for an unknown scope or style, or a missing required id. JavaScript exports the types `ToolScope` and `ToolStyle`.

## Retrieval health

When part of a retrieval fails, a fetch can still succeed with fewer items. The response's `retrieval` block says so, and it is absent on a healthy fetch.

| Field | Values |
| - | - |
| `level` | How thin the answer is: `partial` (some stores answered), `minimal` (only cached results) or `failed`. |
| `code` | Why, so you can decide whether a retry is worth it: `timeout`, `overloaded`, `unavailable` or `internal`. |
| `degraded` | True when something failed. False when the only issue is that you sent more search queries than one fetch runs. |
| `warnings` | One line per part that failed. |

In Python, read `response.retrieval` on the four scoped fetches; it is `None` when the fetch was healthy, and the merged `sdk.fetch` response does not carry it. In JavaScript, the namespaced fetches return the context without this block; only the deprecated camelCase methods, such as `fetchUserContext`, expose it as `retrieval`.

## ID formats

| ID | Format | Checked by |
| - | - | - |
| `conversation_id` | A UUID string: `str(uuid.uuid4())` in Python, `randomUUID()` from `node:crypto` in JavaScript. | SDK: `InvalidConversationIdError`, a subclass of `InvalidInputError`, on `record_message`, `record_messages_batch`, `conversation.context.fetch`, `compact`, `get_compacted`, `get_compaction_status`, `get_context_for_prompt` and `sdk.fetch` (JavaScript checks it up front there; Python checks it when the conversation scope is queried). The user, customer and client fetches and `send_message` pass it through unchecked, so send the same UUID there. |
| `conversation_id` on `ingest_transcript` | Any string, such as a call id. | Not checked. The server converts it to a UUID and returns both: `conversation_id` (the UUID) and `external_conversation_id` (yours). |
| `memory_id` | A UUID. Python's `Memory.memory_id` is a `uuid.UUID`; lists such as `memory_ids` hold strings. | Server: a non-UUID is refused (400, `InvalidInputError`) by `memories.get`, `update` and `delete`. JavaScript also refuses an empty one before sending. |
| `ingestion_id` | A UUID. Python returns a `uuid.UUID`, JavaScript a string. | Server: `memories.status` refuses a non-UUID (400, `InvalidInputError`). JavaScript also refuses an empty one before sending. |
| `instance_id` | `inst_` followed by 16 hexadecimal characters. Normally resolved from your API key. | SDK: if you set one when you construct the client, both SDKs check it there and raise `InvalidInstanceIdError`. |

On a B2C instance, send `user_id` only. Both SDKs refuse a `customer_id` before sending, with `CustomerIdNotAcceptedError`, a subclass of `InvalidInputError`. Before Python 0.5.12 it is a `ValueError` subclass only, so `except InvalidInputError` does not catch it there. The SDK learns whether the instance is B2C from [`initialize()`](/sdk-reference/lifecycle/initialize); JavaScript runs that step on the first request if you skip it. See [B2C vs B2B](/concepts/memory-scopes#b2c-vs-b2b-which-scopes-apply-to-you).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.