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

# Get recommendation sets

> Every recommendation rail on a page in one request.

## Description

A page with several rails, such as "For you", "Similar items" and "Trending", can ask for all of them in one request instead of one request per rail. Each set runs exactly as `GET /v1/recommendations` would run it, so a set returns the same results it would return on its own.

The sets share the work they have in common. The visitor's history is read once for the whole page, and two identical sets in one batch are computed once.

Each set is billed as its own recommendation set, the same as a separate `GET /v1/recommendations` call: a batch of five different sets counts as five. Two identical sets in one batch are computed once and billed once.

## Request

```http theme={null}
POST /v1/recommendations/batch
Content-Type: application/json
```

```json theme={null}
{
  "user_id": "user-abc123",
  "session_id": "session-42",
  "requests": [
    { "key": "for_you", "context_id": 101, "limit": 12 },
    { "key": "similar", "context_id": 102, "item_id": 3187, "limit": 6 },
    { "key": "vans_only", "context_id": 103, "filters": ["type:van"] }
  ]
}
```

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | no | End-user identifier, shared by every set. Falls back to the token subject when omitted. |
| `anonymous_id` | string | no | Anonymous identifier for visitors without a `user_id`. |
| `session_id` | string | no | Session identifier for served-recommendation telemetry. |
| `request_id` | string (UUID) | no | Batch ID. Retrying with the same `request_id` gives each set the same request ID, so a retried page is billed once. |
| `requests` | array | yes | One to eight sets. |

Each set takes:

| Field | Type | Required | Description |
| - | - | - | - |
| `key` | string | yes | Your name for the rail, unique within the batch. Letters, digits, `_`, `.`, `:` and `-`, at most 64 characters. |
| `context_id` | integer | yes | Context ID generated by the dashboard. |
| `limit` | integer | no | Number of recommendations. Defaults to `20`, maximum `100`. A batch holds at most 200 items in total. |
| `item_id` | integer | no | Seed item for item-to-item contexts. |
| `cart_item_ids` | integer\[] | no | Basket items for basket-aware contexts. |
| `page_type` | string | no | Page type, as on `GET /v1/recommendations`. |
| `filters` | string\[] | no | Metadata filter shorthand, as repeated `filter` parameters. |
| `scope` | object | no | Request scope, currently honouring `filters`. |
| `query` | string | no | Runs this set as a [search](https://docs.neuronsearchlab.com/api-reference/endpoint/search.md). |

Pagination (`mode`, `cursor`, `starting_after`) is not part of a batch. Page through a rail with `GET /v1/recommendations`.

## Response

```json theme={null}
{
  "object": "recommendation_set_list",
  "request_id": "0b8e5f4c-8a37-4c1e-9b0f-3d5f2a6c1e90",
  "results": [
    {
      "key": "for_you",
      "status": 200,
      "request_id": "5b6f3f0e-0d1c-5a7e-9f3b-2c1d4e5f6a7b",
      "context_id": 101,
      "object": "list",
      "data": [
        { "id": "7f3a2c9e", "object": "recommendation", "item_id": 3187, "rank": 1, "score": 0.94 }
      ],
      "limit": 12
    },
    {
      "key": "vans_only",
      "status": 404,
      "request_id": "a1d2c3b4-5e6f-5a7b-8c9d-0e1f2a3b4c5d",
      "context_id": 103,
      "error": { "code": "invalid_context", "message": "Context not found" }
    }
  ],
  "usage": { "sets": 3, "computed": 3, "reused": 0, "coalesced": 0 }
}
```

`results` has one entry per set, in request order. A served set carries the same fields as a `GET /v1/recommendations` response, except the duplicate `recommendations` array. Send each set's own `request_id` with the events from that rail so clicks are attributed to it.

A set that fails comes back with its own `status` and `error`, and the other sets are still served. The batch itself fails only when the request is malformed or unauthorised.

`usage.sets` is the number of sets in the batch. `computed`, `reused` and `coalesced` say how many were ranked, served again from an identical answer a moment earlier, or shared with an identical set in the same batch. Computed and reused sets are billed; a coalesced set is not, and it carries the same `request_id` as the set it shares, since it is the same answer. A reused set carries `reuse: { "reused": true, "age_ms": … }` and its own `request_id`.

## SDKs

```ts theme={null}
const { sets } = await sdk.getRecommendationSets({
  userId: 'user-abc123',
  sets: [
    { key: 'for_you', contextId: 101, limit: 12 },
    { key: 'similar', contextId: 102, itemId: 3187, limit: 6 },
  ],
});
```

The TypeScript, PHP and Swift SDKs offer `getRecommendationSets`, and `@neuronsearchlab/nextjs` offers `nsl.recommendSets`. Each one splits a page of more than eight sets into several batches for you. The embed script batches placeholders on the same page automatically.

## Errors

| Status | Scenario |
| - | - |
| `400` | Malformed body, more than eight sets, more than 200 items in total, a duplicate or invalid `key`, or a pagination field in a set |
| `401` | Missing/invalid access token or tenant resolution failed |
| `403` | Token does not include `neuronsearchlab-api/read` |
| `500` | Unexpected failure before any set ran |


## OpenAPI

````yaml POST /v1/recommendations/batch
openapi: 3.0.3
info:
  title: NeuronSearchLab Core API
  version: 1.0.0
  description: >-
    Versioned data-plane API for OAuth token exchange, catalog item ingestion,
    user event ingestion, and recommendation serving.
  license:
    name: Proprietary
    url: https://neuronsearchlab.com
servers:
  - url: https://api.neuronsearchlab.com
    description: Core API Gateway custom domain
security:
  - oauth2: []
tags:
  - name: Authentication
    description: OAuth 2.0 client credentials token exchange.
  - name: Items
    description: Catalog item ingestion, lookup, update, deletion, and pagination.
  - name: Events
    description: User interaction event ingestion, lookup, and pagination.
  - name: Recommendations
    description: >-
      Personalized recommendation serving, request-scoped filtering, and
      auto-section generation.
  - name: CORS
    description: Browser preflight routes generated by API Gateway.
paths:
  /v1/recommendations/batch:
    post:
      tags:
        - Recommendations
      summary: Get recommendation sets
      description: >-
        Every recommendation rail on a page in one request. Each set is billed
        as its own recommendation set.
      operationId: getRecommendationSets
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RecommendationSetsRequest'
            example:
              user_id: user-abc123
              requests:
                - key: for_you
                  context_id: 101
                  limit: 12
                - key: similar
                  context_id: 102
                  item_id: 3187
                  limit: 6
      responses:
        '200':
          description: One result per set
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecommendationSetList'
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '403':
          $ref: '#/components/responses/Error403'
        '500':
          $ref: '#/components/responses/Error500'
      security:
        - oauth2:
            - neuronsearchlab-api/read
components:
  schemas:
    RecommendationSetsRequest:
      type: object
      required:
        - requests
      properties:
        user_id:
          type: string
        anonymous_id:
          type: string
        session_id:
          type: string
        request_id:
          type: string
          format: uuid
          description: Retrying with the same request_id is billed once.
        requests:
          type: array
          minItems: 1
          maxItems: 8
          items:
            $ref: '#/components/schemas/RecommendationSetRequest'
          description: Identical sets in one batch are computed and billed once.
    RecommendationSetList:
      type: object
      required:
        - object
        - request_id
        - results
        - usage
      properties:
        object:
          type: string
          enum:
            - recommendation_set_list
        request_id:
          type: string
          format: uuid
        results:
          type: array
          items:
            $ref: '#/components/schemas/RecommendationSetResult'
          description: One result per request, in request order.
        usage:
          type: object
          required:
            - sets
            - computed
            - reused
            - coalesced
          properties:
            sets:
              type: integer
              description: Sets in the batch.
            computed:
              type: integer
              description: Sets ranked for this request. Billed.
            reused:
              type: integer
              description: Sets served again from an identical recent answer. Billed.
            coalesced:
              type: integer
              description: >-
                Sets identical to an earlier set in the same batch. Not billed
                again; they share its request_id.
    RecommendationSetRequest:
      type: object
      required:
        - key
        - context_id
      additionalProperties: false
      properties:
        key:
          type: string
          pattern: ^[A-Za-z0-9_.:-]{1,64}$
          description: Your name for this rail. Results come back under it.
          example: for_you
        context_id:
          type: integer
          minimum: 1
          description: Context ID generated by the dashboard.
          example: 101
        limit:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
        item_id:
          type: integer
          minimum: 1
          description: Seed item for item-to-item contexts.
        cart_item_ids:
          type: array
          items:
            type: integer
            minimum: 1
        page_type:
          type: string
        filters:
          type: array
          items:
            type: string
          description: >-
            Metadata filter shorthand, as repeated `filter` parameters on GET
            /v1/recommendations.
        scope:
          type: object
          properties:
            filters:
              type: array
              items:
                $ref: '#/components/schemas/ScopeFilter'
        query:
          type: string
          description: Runs this set as a search.
    RecommendationSetResult:
      type: object
      required:
        - key
        - status
        - request_id
        - context_id
      additionalProperties: true
      description: >-
        One set. A served set carries the same fields as a GET
        /v1/recommendations response, except the duplicate `recommendations`
        array. A failed set carries `error` instead.
      properties:
        key:
          type: string
        status:
          type: integer
          example: 200
        request_id:
          type: string
          format: uuid
          description: This set's own request ID, for attributing events.
        context_id:
          type: integer
        data:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/Recommendation'
              - $ref: '#/components/schemas/RecommendationGroup'
        reuse:
          type: object
          properties:
            reused:
              type: boolean
            age_ms:
              type: integer
          description: Present when an identical recent answer was served again.
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
          properties:
            type:
              type: string
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - conflict_error
                - rate_limit_error
                - api_error
            code:
              type: string
            message:
              type: string
            details: {}
            request_id:
              type: string
              format: uuid
          additionalProperties: true
    ScopeFilter:
      type: object
      required:
        - column
        - operator
        - value
      properties:
        column:
          type: string
        operator:
          type: string
          description: Filter operator, such as `=`, `!=`, `<`, `>`, `LIKE`, or `ILIKE`.
        value:
          oneOf:
            - type: string
            - type: number
            - type: boolean
        logic:
          type: string
          enum:
            - AND
            - OR
      additionalProperties: true
    Recommendation:
      type: object
      required:
        - id
        - object
        - item_id
        - rank
        - score
        - item
      properties:
        id:
          type: integer
          minimum: 1
          example: 3187
        object:
          type: string
          enum:
            - recommendation
        item_id:
          type: integer
          minimum: 1
          example: 3187
        entity_id:
          type: integer
          description: Raw item entity ID from the candidate source.
          example: 3187
        rank:
          type: integer
          minimum: 1
          example: 1
        score:
          type: number
          format: double
          example: 0.94
        name:
          type: string
          example: Wireless Headphones
        description:
          type: string
          example: Noise-cancelling Bluetooth headphones.
        metadata:
          $ref: '#/components/schemas/Metadata'
        source:
          type: string
          description: >-
            Candidate source, such as `model`, `trending_backfill`, or
            `exploration`.
          example: model
        item:
          $ref: '#/components/schemas/RecommendationItem'
        explanation:
          $ref: '#/components/schemas/RecommendationExplanation'
      additionalProperties: true
    RecommendationGroup:
      type: object
      required:
        - group
        - items
        - score
      properties:
        group:
          type: string
          description: Group key built from the active context `group_by` fields.
        items:
          type: array
          items:
            $ref: '#/components/schemas/Recommendation'
        score:
          type: number
          format: double
        similarity:
          type: number
          format: double
      additionalProperties: true
    Metadata:
      type: object
      description: Arbitrary JSON object used for filtering, ranking, and debugging.
      additionalProperties: true
      example:
        category: electronics
        brand: Acme
        price: 10999
        currency: usd
    RecommendationItem:
      type: object
      required:
        - id
        - object
        - name
        - description
        - metadata
      properties:
        id:
          type: integer
          minimum: 1
          example: 3187
        object:
          type: string
          enum:
            - item
        name:
          type: string
          example: Wireless Headphones
        description:
          type: string
          example: Noise-cancelling Bluetooth headphones.
        metadata:
          $ref: '#/components/schemas/Metadata'
      additionalProperties: true
    RecommendationExplanation:
      type: object
      properties:
        item_id:
          type: integer
          minimum: 1
        rank:
          type: integer
        summary:
          type: string
        shown_because:
          type: array
          items:
            type: string
        source:
          type: string
        score:
          type: object
          properties:
            final:
              type: number
              nullable: true
            base:
              type: number
              nullable: true
            cosine_distance:
              type: number
              nullable: true
            retrieval:
              type: number
              nullable: true
            ranker:
              type: number
              nullable: true
          additionalProperties: true
        context:
          $ref: '#/components/schemas/ContextExplanation'
        embedding:
          type: object
          additionalProperties: true
        pipeline:
          $ref: '#/components/schemas/PipelineExplanation'
        rules:
          type: array
          items:
            $ref: '#/components/schemas/Object'
        experiments:
          type: array
          items:
            $ref: '#/components/schemas/ExperimentAssignment'
        user_segments:
          type: array
          items:
            type: string
      additionalProperties: true
    ContextExplanation:
      type: object
      properties:
        context_id:
          type: integer
          minimum: 1
          nullable: true
        mode:
          type: string
          enum:
            - single
            - auto
        filters:
          type: array
          items:
            $ref: '#/components/schemas/Object'
        request_filters:
          type: array
          items:
            $ref: '#/components/schemas/ScopeFilter'
        group_by:
          type: array
          items:
            type: string
        exclude_viewed_items:
          type: object
          nullable: true
          properties:
            value:
              type: integer
              nullable: true
            unit:
              type: string
              nullable: true
            interval:
              type: string
              nullable: true
          additionalProperties: true
        auto_section:
          type: object
          nullable: true
          properties:
            section_id:
              type: string
            title:
              type: string
            subtitle:
              type: string
            reason:
              $ref: '#/components/schemas/Object'
          additionalProperties: true
      additionalProperties: true
    PipelineExplanation:
      type: object
      properties:
        id:
          type: integer
          nullable: true
        stages:
          type: array
          items:
            $ref: '#/components/schemas/PipelineStageTrace'
      additionalProperties: true
    Object:
      type: object
      additionalProperties: true
    ExperimentAssignment:
      type: object
      properties:
        experiment_id:
          type: integer
        experiment_name:
          type: string
        variant_id:
          type: integer
        variant_name:
          type: string
      additionalProperties: true
    PipelineStageTrace:
      type: object
      properties:
        stage:
          type: string
        enabled:
          type: boolean
        status:
          type: string
        pipeline_id:
          type: integer
          nullable: true
        config:
          $ref: '#/components/schemas/Object'
        note:
          type: string
        item_events:
          type: array
          items:
            $ref: '#/components/schemas/Object'
      additionalProperties: true
  responses:
    Error400:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            validation:
              $ref: '#/components/examples/ErrorValidation'
    Error401:
      description: Unauthenticated
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              $ref: '#/components/examples/ErrorUnauthorized'
    Error403:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Error500:
      description: Server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  examples:
    ErrorValidation:
      summary: Validation error
      value:
        error:
          type: invalid_request_error
          code: validation_error
          message: Validation error
          details:
            fieldErrors:
              name:
                - Required
    ErrorUnauthorized:
      summary: Unauthorized
      value:
        error:
          type: authentication_error
          code: unauthorized_no_client_id_in_jwt
          message: 'Unauthorized: No client ID in JWT'
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.neuronsearchlab.com/oauth2/token
          scopes:
            neuronsearchlab-api/read: Read recommendations, items, and events.
            neuronsearchlab-api/write: Create, update, and delete items; submit events.

````

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