MemorySyncMemorySync
Core Concepts

Users & Identity

MemorySync has one User table that backs three different identity patterns. The same row represents a dashboard human, a B2B end-user, or an OAuth client-credentials end-user, depending on which fields are populated. This page walks through every identity pattern and the headers that drive them.

User model fields

FieldRole
idInternal numeric primary key. Never exposed in APIs.
public_idStripe-style external id, prefixed usr_. Use this in client code.
external_idOptional. Used by SCIM and B2B end-user mapping.
tenant_idOuter scope key.
emailOptional.
encryption_keyPer-user key for memory ciphertext.
api_keyLegacy field; current API keys live on a separate model.
roleuser, admin, developer.

Three identity patterns, one model

PatternAuthHow the end-user is identified
Dashboard userJWT from /auth/loginThe JWT user is the end-user.
B2B serviceX-API-KeyX-End-User-ID header maps to a User row via composite external_id.
OAuth client-credentialsOAuth bearer tokenX-End-User-ID header same as B2B.

End-user resolution rule

  1. 1If the request is JWT-authenticated, X-End-User-ID is ignored and the JWT subject is used.
  2. 2If the request is API-key-authenticated, X-End-User-ID is required for memory routes; missing it returns 400.
  3. 3The end-user id is combined with the resolved tenant: external_id = "{tenant_id}:{end_user_id}". This composite key prevents collisions across tenants.
  4. 4If no User row matches, the platform creates one on first sight — idempotent on the composite key.

Public id vs internal id

The internal id is an integer primary key that never appears in API responses. The public_id is the opaque usr_-prefixed identifier that does. Always reference users by public_id in client code; assume the internal id can change shape.

Per-user encryption

Every User row carries an encryption_key. Memory text is encrypted with that key on insert and decrypted on read. Deleting a user destroys the key, which makes that user's memories unreadable even if their rows remain.

Roles

FieldAllowed values
User.roleuser, admin, developer.
Membership.role (org)owner, admin, developer, analyst, member, viewer.

User.role is the platform-wide capability; Membership.role scopes capabilities inside one organization.

What not to do with user ids

  • Do not put a body user_id on /memory/add — it is overwritten by the resolved end-user.
  • Do not pass X-End-User-ID from a JWT-authenticated client — it is ignored, and you risk leaking your customer's id into logs.
  • Do not parse public_id for meaning — it is opaque.