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

# Replace the order-routing rules

> Upserts the ENTIRE routing policy. This is a full replacement, not a patch: the `criteria` array you send becomes the whole policy, in the order you send it. Read the rules first and send the full list back with your change applied. The criteria, and the ONLY ones that exist: `stock-depth` (with `direction`: `deepest` — spend the stock the network can most afford to spend — or `shallowest` — drain small positions); `store-priority` (with `storeIds`, best first); and `region-priority` (with `regions`, best first, matched on the store's `region`). There is deliberately NO proximity/distance criterion: an order carries no address and a store carries no coordinates, so distance is not computable from anything in this system. Do not attempt to approximate it with `region-priority` — that is a STATIC merchant preference for certain regions, not a distance to the customer. A criterion kind may appear AT MOST ONCE — a second entry of the same kind could never break a tie the first did not, so it is rejected with a 400 rather than silently ignored. An EMPTY `criteria` array is legal and means 'decide on the lowest store id alone', which is deterministic but almost certainly not what an operator wants; confirm it before sending. This takes effect on the very next order routed anywhere in the network, so it can redirect live fulfilment mid-trading: do not call it speculatively, and confirm the intended policy with the operator first. Note that a store listed in `storeIds` that is DEACTIVATED is simply never a candidate — routing only ever considers trading stores — so prioritising a closed store has no effect rather than reopening it. Returns the policy exactly as persisted.



## OpenAPI

````yaml /openapi.json put /v1/routing-rules
openapi: 3.0.3
info:
  title: Solya POS API
  version: 1.0.0
  description: >-
    The Solya POS backend HTTP surface. Every documented operation is
    agent-ready: it carries an `operationId`, an agent-facing `description`, the
    `pos.*` scopes it enforces (`x-required-permissions`) and an `x-agent-tier`.
    Success responses return the payload as raw JSON; failures return the
    `ErrorResponse` envelope (`{ error: { code, message, statusCode } }`).
servers:
  - url: /
    description: The backend, relative to its deployed origin.
security: []
paths:
  /v1/routing-rules:
    put:
      tags:
        - Settings
      summary: Replace the order-routing rules
      description: >-
        Upserts the ENTIRE routing policy. This is a full replacement, not a
        patch: the `criteria` array you send becomes the whole policy, in the
        order you send it. Read the rules first and send the full list back with
        your change applied. The criteria, and the ONLY ones that exist:
        `stock-depth` (with `direction`: `deepest` — spend the stock the network
        can most afford to spend — or `shallowest` — drain small positions);
        `store-priority` (with `storeIds`, best first); and `region-priority`
        (with `regions`, best first, matched on the store's `region`). There is
        deliberately NO proximity/distance criterion: an order carries no
        address and a store carries no coordinates, so distance is not
        computable from anything in this system. Do not attempt to approximate
        it with `region-priority` — that is a STATIC merchant preference for
        certain regions, not a distance to the customer. A criterion kind may
        appear AT MOST ONCE — a second entry of the same kind could never break
        a tie the first did not, so it is rejected with a 400 rather than
        silently ignored. An EMPTY `criteria` array is legal and means 'decide
        on the lowest store id alone', which is deterministic but almost
        certainly not what an operator wants; confirm it before sending. This
        takes effect on the very next order routed anywhere in the network, so
        it can redirect live fulfilment mid-trading: do not call it
        speculatively, and confirm the intended policy with the operator first.
        Note that a store listed in `storeIds` that is DEACTIVATED is simply
        never a candidate — routing only ever considers trading stores — so
        prioritising a closed store has no effect rather than reopening it.
        Returns the policy exactly as persisted.
      operationId: updateRoutingRules
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                criteria:
                  type: array
                  items:
                    oneOf:
                      - type: object
                        properties:
                          kind:
                            type: string
                            enum:
                              - stock-depth
                          direction:
                            type: string
                            enum:
                              - deepest
                              - shallowest
                        required:
                          - kind
                          - direction
                      - type: object
                        properties:
                          kind:
                            type: string
                            enum:
                              - store-priority
                          storeIds:
                            maxItems: 500
                            type: array
                            items:
                              type: string
                              minLength: 1
                        required:
                          - kind
                          - storeIds
                      - type: object
                        properties:
                          kind:
                            type: string
                            enum:
                              - region-priority
                          regions:
                            maxItems: 500
                            type: array
                            items:
                              type: string
                              minLength: 1
                        required:
                          - kind
                          - regions
              required:
                - criteria
              example:
                criteria:
                  - kind: store-priority
                    storeIds:
                      - shop-paris
                      - shop-lyon
                  - kind: region-priority
                    regions:
                      - Île-de-France
                  - kind: stock-depth
                    direction: deepest
      responses:
        '200':
          description: >-
            The routing policy as it was persisted (identical to the request
            body).
          content:
            application/json:
              schema:
                type: object
                properties:
                  criteria:
                    type: array
                    items:
                      oneOf:
                        - type: object
                          properties:
                            kind:
                              type: string
                              enum:
                                - stock-depth
                            direction:
                              type: string
                              enum:
                                - deepest
                                - shallowest
                          required:
                            - kind
                            - direction
                          additionalProperties: false
                        - type: object
                          properties:
                            kind:
                              type: string
                              enum:
                                - store-priority
                            storeIds:
                              maxItems: 500
                              type: array
                              items:
                                type: string
                                minLength: 1
                          required:
                            - kind
                            - storeIds
                          additionalProperties: false
                        - type: object
                          properties:
                            kind:
                              type: string
                              enum:
                                - region-priority
                            regions:
                              maxItems: 500
                              type: array
                              items:
                                type: string
                                minLength: 1
                          required:
                            - kind
                            - regions
                          additionalProperties: false
                required:
                  - criteria
                additionalProperties: false
                description: >-
                  The routing policy as it was persisted (identical to the
                  request body).
                example:
                  criteria:
                    - kind: store-priority
                      storeIds:
                        - shop-paris
                        - shop-lyon
                    - kind: region-priority
                      regions:
                        - Île-de-France
                    - kind: stock-depth
                      direction: deepest
        '400':
          description: >-
            The request failed schema validation; `error.fieldErrors` lists the
            fields.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
        '401':
          description: No valid credential was presented — send a bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The actor is authenticated but lacks the required `pos.*` scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: An unexpected server error — safe to retry idempotent requests.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    ValidationErrorResponse:
      type: object
      required:
        - error
      additionalProperties: false
      description: >-
        A `VALIDATION_FAILED` envelope carrying the offending fields in
        `fieldErrors`.
      properties:
        error:
          type: object
          required:
            - code
            - message
            - statusCode
          additionalProperties: false
          properties:
            code:
              type: string
              enum:
                - VALIDATION_FAILED
            message:
              type: string
            statusCode:
              type: integer
            fieldErrors:
              type: array
              description: >-
                One entry per rejected field: the field path and why it was
                rejected.
              items:
                type: object
                required:
                  - field
                  - message
                additionalProperties: false
                properties:
                  field:
                    type: string
                    description: Dot-path of the offending field.
                  message:
                    type: string
                    description: Why the field was rejected.
    ErrorResponse:
      type: object
      required:
        - error
      additionalProperties: false
      description: The uniform failure envelope every non-2xx response returns.
      properties:
        error:
          type: object
          required:
            - code
            - message
            - statusCode
          additionalProperties: false
          properties:
            code:
              type: string
              enum:
                - VALIDATION_FAILED
                - UNAUTHORIZED
                - FORBIDDEN
                - NOT_FOUND
                - CONFLICT
                - BUSINESS_RULE_VIOLATION
                - INTERNAL_ERROR
              description: >-
                Machine-readable kernel `ResultCode` — branch on this, not on
                `message`.
            message:
              type: string
              description: >-
                Human-readable explanation. Safe to surface; never leaks server
                internals.
            statusCode:
              type: integer
              description: >-
                The HTTP status, mirrored into the body so a client need not
                read headers.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        `Authorization: Bearer <token>`. Accepts EITHER a Keycloak access token
        (scopes-in-token) OR an opaque POS session token; both resolve to the
        same `pos.*` scope vocabulary the route guards enforce.

````