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

# Upsert user

> Create or update a user with raw context, structured fields, or an external memory reference.

Use this when a user **first enters your system**. Send whatever context you have, in any form:

* **Free text** in `context` (resume, intake transcript, profile blurb). The platform extracts fields against your domain schema.
* **Pre-structured `fields`** when you already have typed values. Skips extraction.
* **`memory_ref`** pointing at an external store you operate (Jean Memory, Mem0, or your own vector DB).

You can mix all three in one call. Anything in `fields` wins over anything extracted from `context`.

For incremental updates later (a new chat message, a follow-up call), use [`POST /context`](/api-reference/users/append-context) instead so you don't re-send the whole user.

<CodeGroup>
  ```bash curl theme={"dark"}
  curl https://api.jeantechnologies.com/v1/users \
    -H "Authorization: Bearer $JEAN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "user_id": "u_alice",
      "domain": "dating",
      "context": "32, NYC, looking for someone serious. Reads a lot, runs in the park, vegetarian.",
      "fields": { "location": "New York, NY" }
    }'
  ```

  ```python Python theme={"dark"}
  import os, requests

  requests.post(
      "https://api.jeantechnologies.com/v1/users",
      headers={"Authorization": f"Bearer {os.environ['JEAN_API_KEY']}"},
      json={
          "user_id": "u_alice",
          "domain": "dating",
          "context": "32, NYC, looking for someone serious. Reads a lot, runs in the park, vegetarian.",
          "fields": {"location": "New York, NY"},
      },
  ).json()
  ```

  ```ts TypeScript theme={"dark"}
  const res = await fetch("https://api.jeantechnologies.com/v1/users", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.JEAN_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      user_id: "u_alice",
      domain: "dating",
      context:
        "32, NYC, looking for someone serious. Reads a lot, runs in the park, vegetarian.",
      fields: { location: "New York, NY" },
    }),
  });
  const user = await res.json();
  ```
</CodeGroup>

## Example response

```json theme={"dark"}
{
  "user_id": "u_alice",
  "domain": "dating",
  "schema_version": "dating.v3",
  "fields": {
    "age": 32,
    "location": "New York, NY",
    "relationship_goal": "serious"
  },
  "derived": {
    "attachment_style": "secure"
  },
  "embeddings": {
    "dating": { "dim": 1024, "version": "dating-2026-05-01" }
  },
  "last_enriched_at": "2026-05-17T22:01:09Z"
}
```

The `embeddings` object lists each domain head this user now has a vector for. After a single upsert in `dating`, only the dating head is populated. Other heads materialize lazily when the user is matched against in another domain.

## Common pitfalls

<AccordionGroup>
  <Accordion title="My extracted fields are empty" icon="circle-question">
    Either the schema for this domain has no extraction rules yet (we co-design it during onboarding) or the `context` was too sparse to ground anything. Run `GET /schema?domain=...` to inspect what the platform is trying to extract.
  </Accordion>

  <Accordion title="Fields I sent don't match the schema" icon="circle-exclamation">
    Unrecognized field keys are stored under `extras` and not used for ranking. Add them to the schema at onboarding or strip them before sending.
  </Accordion>

  <Accordion title="Upsert vs. partial update" icon="arrows-rotate">
    `POST /users` replaces the user's row entirely (subject to merging logic on provenance). For non-destructive incremental updates, use `POST /context`.
  </Accordion>
</AccordionGroup>


## OpenAPI

````yaml POST /users
openapi: 3.1.0
info:
  title: Jean Technologies API
  version: 1.0.0
  description: >-
    Matching infrastructure for AI-era platforms. Ingest user context, retrieve
    compatible candidates, send outcomes back.
servers:
  - url: https://api.jeantechnologies.com/v1
    description: Production
security:
  - bearerAuth: []
paths:
  /users:
    post:
      tags:
        - Users
      summary: Upsert user
      description: >-
        Ingest a user into the platform. Pass `context` for free-text
        extraction, `fields` for pre-structured data, or both. Users are scoped
        to a `domain`.
      operationId: upsertUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertUserRequest'
      responses:
        '200':
          description: User upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  schemas:
    UpsertUserRequest:
      type: object
      required:
        - user_id
        - domain
      properties:
        user_id:
          type: string
          description: Client-supplied unique identifier.
          example: u_alice
        domain:
          type: string
          description: Domain this user belongs to (e.g. dating, hiring).
          example: dating
        context:
          type: string
          description: Free-text context. The platform extracts structured fields from it.
          example: >-
            32, NYC, looking for someone serious. Reads a lot, runs in the park,
            vegetarian.
        fields:
          type: object
          additionalProperties: true
          description: Pre-structured field values. Overrides any conflicting extraction.
          example:
            age: 32
            location: New York, NY
        memory_ref:
          type: string
          description: >-
            Optional pointer to an external memory or context store the customer
            operates.
          example: jeanmemory://tenant/u_alice
    User:
      type: object
      properties:
        user_id:
          type: string
          example: u_alice
        domain:
          type: string
          example: dating
        schema_version:
          type: string
          example: dating.v3
        fields:
          type: object
          additionalProperties: true
          example:
            age: 32
            location: New York, NY
            relationship_goal: serious
        derived:
          type: object
          additionalProperties: true
          example:
            attachment_style: secure
        embeddings:
          type: object
          additionalProperties:
            type: object
            properties:
              dim:
                type: integer
              version:
                type: string
          example:
            dating:
              dim: 1024
              version: dating-2026-05-01
        last_enriched_at:
          type: string
          format: date-time
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: invalid_request
            message:
              type: string
              example: Field 'domain' is required.
            details:
              type: object
              additionalProperties: true
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key issued by Jean Technologies. Contact the team for access.

````