> ## 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.

# Match

> Run the matching pipeline for a user and return ranked compatible candidates.

The value moment. Given a `user_id` and a `domain`, the platform runs the pipeline against the most specific [model](/models) available for your tenant (general → domain → tenant-tuned):

```
SQL filter → light ML rerank → domain embedding → cross-encoder → optional LLM judge
```

Each stage hands a smaller candidate set to the next so the expensive stages only see candidates worth their time. You can toggle or tune any stage per request.

<CodeGroup>
  ```bash curl theme={"dark"}
  curl https://api.jeantechnologies.com/v1/match \
    -H "Authorization: Bearer $JEAN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "user_id": "u_alice",
      "domain": "dating",
      "limit": 10,
      "filters": { "location_within_km": 50 }
    }'
  ```

  ```python Python theme={"dark"}
  matches = requests.post(
      "https://api.jeantechnologies.com/v1/match",
      headers={"Authorization": f"Bearer {os.environ['JEAN_API_KEY']}"},
      json={
          "user_id": "u_alice",
          "domain": "dating",
          "limit": 10,
          "filters": {"location_within_km": 50},
      },
  ).json()
  ```

  ```ts TypeScript theme={"dark"}
  const res = await fetch("https://api.jeantechnologies.com/v1/match", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.JEAN_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      user_id: "u_alice",
      domain: "dating",
      limit: 10,
      filters: { location_within_km: 50 },
    }),
  });
  const { matches } = await res.json();
  ```
</CodeGroup>

## Tuning the pipeline

The `stages` object accepts a boolean shortcut or a per-stage config. Mix freely.

```json theme={"dark"}
{
  "user_id": "u_alice",
  "domain": "dating",
  "stages": {
    "llm_judge": true,
    "cross_encoder": { "enabled": true, "top_k": 25 },
    "light_ml":      { "min_score": 0.3 }
  },
  "explain": true
}
```

| Stage           | Default | Per-candidate cost | When to tune                                              |
| --------------- | ------- | ------------------ | --------------------------------------------------------- |
| `sql_filter`    | on      | microseconds       | only off for debugging                                    |
| `light_ml`      | on      | milliseconds       | raise `min_score` to be stricter                          |
| `embedding`     | on      | sub-ms (ANN)       | almost always on; required for quality                    |
| `cross_encoder` | on      | \~10ms             | lower `top_k` for latency, raise for quality              |
| `llm_judge`     | off     | seconds            | turn on when prompt-fit or free-text deal-breakers matter |

Set `"explain": true` to get per-candidate `stage_scores` and human-readable reasons in the response.

## Example response

```json theme={"dark"}
{
  "matches": [
    {
      "user_id": "c_456",
      "score": 0.87,
      "stage_scores": {
        "light_ml": 0.71,
        "embedding": 0.84,
        "cross_encoder": 0.87
      },
      "reasons": [
        "shared communication style",
        "compatible relationship goals"
      ]
    }
  ],
  "pipeline_stats": {
    "after_sql_filter": 12431,
    "after_light_ml": 412,
    "after_embedding": 53,
    "after_cross_encoder": 10
  }
}
```

`pipeline_stats` lets you see, per request, how the candidate pool narrowed. Useful when tuning: if `after_light_ml` is too small, your `min_score` is too aggressive. If `after_sql_filter` is huge, your hard filters aren't pulling their weight.

<Warning>
  Latency budget: with `llm_judge` off, p99 is typically under 200ms on a 10M-user index. Turning the judge on adds 1-3 seconds per request. Reserve it for the final-decision call, not exploratory queries.
</Warning>


## OpenAPI

````yaml POST /match
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:
  /match:
    post:
      tags:
        - Matching
      summary: Match
      description: >-
        Run the matching pipeline (SQL filter, light ML, dense embedding,
        cross-encoder, optional LLM judge) for a user.
      operationId: match
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatchRequest'
      responses:
        '200':
          description: Ranked candidates
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  schemas:
    MatchRequest:
      type: object
      required:
        - user_id
        - domain
      properties:
        user_id:
          type: string
          example: u_alice
        domain:
          type: string
          example: dating
        limit:
          type: integer
          default: 10
          minimum: 1
          maximum: 100
          example: 10
        filters:
          type: object
          additionalProperties: true
          description: Hard constraints applied before ranking.
          example:
            location_within_km: 50
        stages:
          type: object
          description: >-
            Per-stage controls. Each stage can be toggled on or off, or passed a
            config object for finer control. Omit the whole object to accept
            sensible defaults for the domain.
          properties:
            sql_filter:
              $ref: '#/components/schemas/StageToggle'
              description: >-
                Hard constraints from the schema and request filters.
                Microseconds per candidate. Off only for debugging.
            light_ml:
              $ref: '#/components/schemas/StageToggle'
              description: >-
                Sparse-feature gradient-boosted reranker. Milliseconds per
                candidate. Cuts tens of thousands to hundreds.
            embedding:
              $ref: '#/components/schemas/StageToggle'
              description: >-
                Domain-adapted dual-encoder ANN search. Sub-millisecond per
                candidate. Required for any non-trivial result quality.
            cross_encoder:
              $ref: '#/components/schemas/StageToggle'
              description: >-
                Interaction-aware reranker on the surviving top-K. ~10ms per
                candidate. Recommended on for quality, off for raw latency.
            llm_judge:
              $ref: '#/components/schemas/StageToggle'
              description: >-
                Last-mile LLM scoring on the final 5-10 candidates. Seconds per
                candidate. Off by default; turn on when prompt-fit or free-text
                deal-breakers matter.
          example:
            llm_judge: true
            cross_encoder:
              enabled: true
              top_k: 25
        explain:
          type: boolean
          default: false
          description: >-
            If true, response includes per-stage stage_scores and human-readable
            reasons for each candidate.
    MatchResponse:
      type: object
      properties:
        matches:
          type: array
          items:
            $ref: '#/components/schemas/Match'
        pipeline_stats:
          type: object
          properties:
            after_sql_filter:
              type: integer
              example: 12431
            after_light_ml:
              type: integer
              example: 412
            after_embedding:
              type: integer
              example: 53
            after_cross_encoder:
              type: integer
              example: 10
        models_used:
          type: object
          description: >-
            Which model tier and version served each stage. Log alongside
            outcomes to attribute lift to a specific deploy.
          additionalProperties:
            type: object
            properties:
              tier:
                type: string
                enum:
                  - general
                  - domain
                  - tenant
              version:
                type: string
          example:
            embedding:
              tier: tenant
              version: u_acme.dating.2026-05-17
            cross_encoder:
              tier: domain
              version: dating.cx.2026-05-01
    StageToggle:
      oneOf:
        - type: boolean
          description: 'Shortcut: true enables the stage with defaults, false disables it.'
        - type: object
          properties:
            enabled:
              type: boolean
              default: true
            top_k:
              type: integer
              description: How many candidates to forward to the next stage.
            min_score:
              type: number
              description: >-
                Drop candidates whose score in this stage falls below this
                threshold.
            model:
              type: string
              description: >-
                Pin to a model tier (`general`, `domain`, `tenant`) or a
                specific version string. Defaults to the most specific tier
                available for your tenant. See the Models page for tier
                semantics.
              example: tenant
    Match:
      type: object
      properties:
        user_id:
          type: string
          example: c_456
        score:
          type: number
          format: float
          example: 0.87
        stage_scores:
          type: object
          additionalProperties:
            type: number
          example:
            light_ml: 0.71
            embedding: 0.84
            cross_encoder: 0.87
        reasons:
          type: array
          items:
            type: string
          example:
            - shared communication style
            - compatible relationship goals
    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.

````