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

# Register a decision structure

> Stores a structure under the decision so evaluations can name it in `moonbounce.structure_hash`. Idempotent by content: 201 when this call registered it, 200 when it already existed. The first registration for an environment also creates the decision's engine binding there from the deployment default. Returns hashes without the structure; getStructure reads it.



## OpenAPI

````yaml /openapi.json post /v1/decisions/{decision_id}/structures
openapi: 3.1.0
info:
  title: Moonbounce Decisions API
  version: 0.0.0
  description: >-
    Moonbounce decisions: evaluate an item's state against a decision structure
    (System One questions, attributes you supply and aggregations over both),
    record feedback and seed examples, review a ranked queue, and improve the
    structure through suggestions that ship as code diffs, each with a preview
    (backtest) and an evidence label.


    **Authentication.** Send an API key as `Authorization: Bearer <key>` on
    every operation except `GET /health` and `POST /v1/structures/hash`. Call
    the API from a server, never a browser: a key must not reach one, and the
    API sends no CORS headers. A key belongs to one organization and one
    environment: production, or test for a key with the `env:test` permission.
    Test traffic never counts as production traffic.


    **Requests.** JSON bodies (`Content-Type: application/json`) of at most 1
    MB, parsed strictly: duplicate keys, lone surrogates, integers outside
    ±(2^53 - 1), `__proto__` keys, U+0000 and nesting deeper than 64 are a 400.


    **Retries.** Send an `Idempotency-Key` on every POST under /v1 that takes
    one (all but `POST /v1/structures/hash`). Keep it for the request's retries.
    The same key with the same request returns the first stored result, marked
    `Idempotent-Replayed: true`, for 24 hours (410 if that result was since
    deleted); with another request it is 422 IDEMPOTENCY_KEY_REUSED. Keys are
    scoped to the organization and environment across every operation, so use a
    fresh key per request. A request that failed before its result was stored
    runs again when retried. 429 and 503 under /v1 may carry `Retry-After`
    (seconds); a daily QUOTA_EXCEEDED cap instead names its reset time.


    **Errors.** Every error under /v1 is `{"error": {"type", "message",
    "reason"?, "param"?, "details"?}}` (ErrorBody); `GET /health` answers its
    own shape. Every response carries a `Request-Id` header. Rate limits apply
    per key, and per client IP for requests without a valid key; a 429
    RATE_LIMITED carries `Retry-After`.
servers:
  - url: https://api.moonbounce.ai
    description: Production
security: []
paths:
  /v1/decisions/{decision_id}/structures:
    post:
      tags:
        - structures
      summary: Register a decision structure
      description: >-
        Stores a structure under the decision so evaluations can name it in
        `moonbounce.structure_hash`. Idempotent by content: 201 when this call
        registered it, 200 when it already existed. The first registration for
        an environment also creates the decision's engine binding there from the
        deployment default. Returns hashes without the structure; getStructure
        reads it.
      operationId: registerStructure
      parameters:
        - schema:
            $ref: '#/components/schemas/DecisionId'
          required: true
          name: decision_id
          in: path
        - schema:
            type: string
            minLength: 1
            maxLength: 255
            pattern: ^[\x20-\x7e]+$
            description: >-
              Makes a retry safe. For 24 hours, the same key with the same
              request returns the first stored result (with Idempotent-Replayed:
              true); the same key with a different request is a 422
              IDEMPOTENCY_KEY_REUSED. Keys are scoped to the organization and
              environment across every operation, so use a fresh key per
              request. A request that failed before its result was stored runs
              again when retried with its key.
          required: false
          description: >-
            Makes a retry safe. For 24 hours, the same key with the same request
            returns the first stored result (with Idempotent-Replayed: true);
            the same key with a different request is a 422
            IDEMPOTENCY_KEY_REUSED. Keys are scoped to the organization and
            environment across every operation, so use a fresh key per request.
            A request that failed before its result was stored runs again when
            retried with its key.
          name: idempotency-key
          in: header
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DecisionStructure'
      responses:
        '200':
          description: Already registered
          headers:
            Idempotent-Replayed:
              schema:
                type: string
                enum:
                  - 'true'
                description: >-
                  Present and `true` when this is the stored result of an
                  earlier request with the same Idempotency-Key.
              required: false
              description: >-
                Present and `true` when this is the stored result of an earlier
                request with the same Idempotency-Key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StructureRecord'
        '201':
          description: Registered
          headers:
            Idempotent-Replayed:
              schema:
                type: string
                enum:
                  - 'true'
                description: >-
                  Present and `true` when this is the stored result of an
                  earlier request with the same Idempotency-Key.
              required: false
              description: >-
                Present and `true` when this is the stored result of an earlier
                request with the same Idempotency-Key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StructureRecord'
        '400':
          description: 'Invalid request: `param` names the field at fault when one applies'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '401':
          description: Missing or invalid API key (reason KEY_INVALID)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: The key may not do this
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '410':
          description: >-
            The Idempotency-Key's first result was deleted, so it cannot be
            replayed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '413':
          description: The HTTP body exceeds 1 MB (reason BODY_TOO_LARGE)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: >-
            The request is well formed but cannot be processed
            (IDEMPOTENCY_KEY_REUSED requires a fresh key; REQUEST_TOO_LARGE
            requires a smaller request)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '429':
          description: >-
            RATE_LIMITED: retry after Retry-After seconds; QUOTA_EXCEEDED:
            details.reset_at gives the daily reset time (no Retry-After)
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: false
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: >-
            Temporarily unavailable, with Retry-After (for example reason
            AUTH_UNAVAILABLE, ENGINE_UNAVAILABLE or STORE_UNAVAILABLE): retry
            with the same Idempotency-Key
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: true
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      security:
        - bearerAuth:
            - decisions:develop
components:
  schemas:
    DecisionId:
      type: string
      pattern: ^[a-z][a-z0-9_.-]{0,127}$
    DecisionStructure:
      type: object
      properties:
        questions:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/Question'
          description: System One questions, keyed by name.
        attributes:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/Attribute'
          description: >-
            Values your app supplies with each call in `attribute_values`. The
            model never sees them.
        aggregations:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/Aggregation'
        result:
          type: string
          minLength: 1
          maxLength: 80
          description: The final feature's path, such as `aggregations.band`.
          examples:
            - questions.asks_for_refund
            - aggregations.band
      required:
        - questions
        - result
      additionalProperties: false
      description: >-
        Everything that defines a decision: questions, attribute declarations,
        aggregations and the result. Names are unique across all three maps.
    StructureRecord:
      type: object
      properties:
        environment:
          $ref: '#/components/schemas/Environment'
        decision_id:
          $ref: '#/components/schemas/DecisionIdOutput'
        structure_hash:
          $ref: '#/components/schemas/StructureHashOutput'
        question_hashes:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/QuestionHash'
          description: >-
            Each question, by name, mapped to its hash (its definition without
            its name). A question's hash is what feedback about it is stored
            against.
        first_seen_at:
          $ref: '#/components/schemas/Timestamp'
        created:
          type: boolean
      required:
        - environment
        - decision_id
        - structure_hash
        - question_hashes
        - first_seen_at
        - created
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    ErrorBody:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              $ref: '#/components/schemas/ErrorType'
            reason:
              type: string
              pattern: ^[A-Z][A-Z0-9_]+$
              description: >-
                Set where a caller can act on it, one of the reasons in the
                ErrorReason schema. New reasons may be added: treat an unknown
                one by the status and `type`.
            message:
              type: string
              description: For people; don't parse it.
            param:
              type: string
              description: >-
                The request field at fault, as a dotted path
                (`attribute_values.region`, `claims.1.value`).
            details:
              type: object
              properties:
                issues:
                  type: array
                  items:
                    $ref: '#/components/schemas/ErrorIssue'
              additionalProperties: {}
          required:
            - type
            - message
          additionalProperties: true
          x-moonbounce-sdk-known-fields: true
      required:
        - error
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    Question:
      oneOf:
        - $ref: '#/components/schemas/NoulQuestion'
      discriminator:
        propertyName: type
        mapping:
          noul: '#/components/schemas/NoulQuestion'
    Attribute:
      oneOf:
        - $ref: '#/components/schemas/StringAttribute'
        - $ref: '#/components/schemas/NumberAttribute'
        - $ref: '#/components/schemas/BooleanAttribute'
      discriminator:
        propertyName: type
        mapping:
          string: '#/components/schemas/StringAttribute'
          number: '#/components/schemas/NumberAttribute'
          boolean: '#/components/schemas/BooleanAttribute'
    Aggregation:
      oneOf:
        - $ref: '#/components/schemas/WeightedMean'
        - $ref: '#/components/schemas/Logistic'
        - $ref: '#/components/schemas/Min'
        - $ref: '#/components/schemas/Max'
        - $ref: '#/components/schemas/Product'
        - $ref: '#/components/schemas/NoisyOr'
        - $ref: '#/components/schemas/All'
        - $ref: '#/components/schemas/Any'
        - $ref: '#/components/schemas/Bands'
        - $ref: '#/components/schemas/Rules'
        - $ref: '#/components/schemas/Match'
      discriminator:
        propertyName: type
        mapping:
          weighted_mean: '#/components/schemas/WeightedMean'
          logistic: '#/components/schemas/Logistic'
          min: '#/components/schemas/Min'
          max: '#/components/schemas/Max'
          product: '#/components/schemas/Product'
          noisy_or: '#/components/schemas/NoisyOr'
          all: '#/components/schemas/All'
          any: '#/components/schemas/Any'
          bands: '#/components/schemas/Bands'
          rules: '#/components/schemas/Rules'
          match: '#/components/schemas/Match'
    Environment:
      type: string
      enum:
        - production
        - test
      description: >-
        The environment of the key that made the call: `production` or `test`.
        Evaluations, feedback, reviews and suggestions are separate per
        environment; registered structures are shared.
    DecisionIdOutput:
      type: string
      pattern: ^[a-z][a-z0-9_.-]{0,127}$
    StructureHashOutput:
      type: string
      pattern: ^sha256:[0-9a-f]{64}$
    QuestionHash:
      type: string
      pattern: ^sha256:[0-9a-f]{64}$
    Timestamp:
      type: string
      format: date-time
    ErrorType:
      type: string
      enum:
        - invalid_request
        - authentication
        - permission_denied
        - not_found
        - conflict
        - rate_limited
        - engine_failed
        - unavailable
        - internal
    ErrorIssue:
      type: object
      properties:
        param:
          type: string
        code:
          type: string
          pattern: ^[A-Z][A-Z0-9_]+$
          description: >-
            Stable, extensible issue code; unknown codes still have a parameter
            and human-readable message.
        message:
          type: string
      required:
        - param
        - code
        - message
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    NoulQuestion:
      type: object
      properties:
        type:
          type: string
          enum:
            - noul
        instructions:
          $ref: '#/components/schemas/Instructions'
        criteria:
          type: object
          properties:
            'true':
              type: string
              minLength: 1
              maxLength: 4000
            'false':
              type: string
              minLength: 1
              maxLength: 4000
          additionalProperties: false
        reads:
          type: array
          items:
            $ref: '#/components/schemas/StatePath'
          minItems: 1
          maxItems: 64
          description: >-
            Paths into an object `state` this question reads, such as
            `state.message` or `state.order.customer.tier`. The question sees
            just those values, nested as in the state. Without it the question
            sees the whole state, as in System One. Every path must exist in the
            call's `state`; no entry may repeat or contain another.
      required:
        - type
        - instructions
      additionalProperties: false
      description: P(true) for a statement about the state.
    StringAttribute:
      type: object
      properties:
        type:
          type: string
          enum:
            - string
        enum:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 200
          minItems: 1
          maxItems: 255
        default:
          type: string
        source:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            The model and version behind this attribute, such as
            `toxicity-classifier-v3`. Hashed.
      required:
        - type
        - enum
      additionalProperties: false
    NumberAttribute:
      type: object
      properties:
        type:
          type: string
          enum:
            - number
        minimum:
          type: number
        maximum:
          type: number
        default:
          type: number
        source:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            The model and version behind this attribute, such as
            `toxicity-classifier-v3`. Hashed.
      required:
        - type
      additionalProperties: false
    BooleanAttribute:
      type: object
      properties:
        type:
          type: string
          enum:
            - boolean
        default:
          type: boolean
        source:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            The model and version behind this attribute, such as
            `toxicity-classifier-v3`. Hashed.
      required:
        - type
      additionalProperties: false
    WeightedMean:
      type: object
      properties:
        type:
          type: string
          enum:
            - weighted_mean
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              weight:
                type: number
                exclusiveMinimum: 0
              invert:
                type: boolean
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 'Σ wᵢ·xᵢ / Σ wᵢ: a weighted average from 0 to 1, not a probability.'
    Logistic:
      type: object
      properties:
        type:
          type: string
          enum:
            - logistic
        bias:
          type: number
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              weight:
                type: number
            required:
              - name
              - weight
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - bias
        - inputs
      additionalProperties: false
      description: σ(bias + Σ wᵢ·xᵢ), with signed weights on raw input values.
    Min:
      type: object
      properties:
        type:
          type: string
          enum:
            - min
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              invert:
                type: boolean
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 'min xᵢ: all of these, when they overlap.'
    Max:
      type: object
      properties:
        type:
          type: string
          enum:
            - max
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              invert:
                type: boolean
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 'max xᵢ: any of these, when they overlap.'
    Product:
      type: object
      properties:
        type:
          type: string
          enum:
            - product
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              invert:
                type: boolean
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 'Π xᵢ: all of these, when they are independent.'
    NoisyOr:
      type: object
      properties:
        type:
          type: string
          enum:
            - noisy_or
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              invert:
                type: boolean
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: '1 − Π(1 − xᵢ): any of these, when they are independent.'
    All:
      type: object
      properties:
        type:
          type: string
          enum:
            - all
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              gte:
                type: number
              gt:
                type: number
              lte:
                type: number
              lt:
                type: number
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 1 when every input passes its threshold (default ≥ 0.5), else 0.
    Any:
      type: object
      properties:
        type:
          type: string
          enum:
            - any
        inputs:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/FeatureRef'
              gte:
                type: number
              gt:
                type: number
              lte:
                type: number
              lt:
                type: number
            required:
              - name
            additionalProperties: false
          minItems: 1
          maxItems: 64
      required:
        - type
        - inputs
      additionalProperties: false
      description: 1 when any input passes its threshold (default ≥ 0.5), else 0.
    Bands:
      type: object
      properties:
        type:
          type: string
          enum:
            - bands
        input:
          $ref: '#/components/schemas/FeatureRef'
        below:
          $ref: '#/components/schemas/Name'
        cuts:
          type: array
          items:
            type: object
            properties:
              at:
                type: number
              outcome:
                $ref: '#/components/schemas/Name'
            required:
              - at
              - outcome
            additionalProperties: false
          minItems: 1
          maxItems: 9
        abstain:
          $ref: '#/components/schemas/Name'
      required:
        - type
        - input
        - below
        - cuts
      additionalProperties: false
      description: >-
        Names an outcome for each range of one feature's value. `at` means ≥;
        `below` is under the first cut.
    Rules:
      type: object
      properties:
        type:
          type: string
          enum:
            - rules
        rules:
          type: array
          items:
            type: object
            properties:
              when:
                $ref: '#/components/schemas/Condition'
              outcome:
                $ref: '#/components/schemas/Name'
            required:
              - when
              - outcome
            additionalProperties: false
          minItems: 1
          maxItems: 64
        else:
          $ref: '#/components/schemas/Name'
      required:
        - type
        - rules
        - else
      additionalProperties: false
      description: >-
        The first rule whose condition is true names its `outcome`; otherwise
        `else`.
    Match:
      type: object
      properties:
        type:
          type: string
          enum:
            - match
        input:
          $ref: '#/components/schemas/FeatureRef'
        cases:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/Name'
          description: >-
            Maps labels to outcomes. "__proto__" is not supported as a case key;
            use a rules is-condition for that label.
        else:
          $ref: '#/components/schemas/Name'
        abstain:
          $ref: '#/components/schemas/Name'
      required:
        - type
        - input
        - cases
      additionalProperties: false
      description: Maps a label straight to an outcome.
    Instructions:
      anyOf:
        - type: string
          minLength: 1
          maxLength: 4000
        - type: object
          additionalProperties: {}
        - type: array
          items: {}
          minItems: 1
    StatePath:
      type: string
      minLength: 1
      maxLength: 256
      description: >-
        `state.<key>` or a nested object path such as
        `state.order.customer.tier`: keys of an object `state`. A key has no
        `.`, `[` or `]`. Array indexes are not supported yet.
      examples:
        - state.message
        - state.order.order_total_usd
    FeatureRef:
      type: string
      minLength: 1
      maxLength: 80
      description: >-
        A feature's path: `questions.<name>`, `attributes.<name>` or
        `aggregations.<name>`.
      examples:
        - questions.asks_for_refund
        - aggregations.band
    Name:
      type: string
      pattern: ^[a-z][a-z0-9_]{0,63}$
    Condition:
      anyOf:
        - type: object
          properties:
            name:
              $ref: '#/components/schemas/FeatureRef'
            gte:
              type: number
            gt:
              type: number
            lte:
              type: number
            lt:
              type: number
            is:
              type: string
              minLength: 1
              maxLength: 200
            in:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 200
              minItems: 1
              maxItems: 255
            abstained:
              type: boolean
              enum:
                - true
          required:
            - name
          additionalProperties: false
        - type: object
          properties:
            all:
              type: array
              items:
                $ref: '#/components/schemas/Condition'
              minItems: 1
              maxItems: 64
          required:
            - all
          additionalProperties: false
        - type: object
          properties:
            any:
              type: array
              items:
                $ref: '#/components/schemas/Condition'
              minItems: 1
              maxItems: 64
          required:
            - any
          additionalProperties: false
        - type: object
          properties:
            not:
              $ref: '#/components/schemas/Condition'
          required:
            - not
          additionalProperties: false
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key, sent as `Authorization: Bearer <key>`. Each operation lists
        the scope its key needs: `decisions:evaluate` (evaluate and read
        evaluations), `decisions:feedback` (your app's feedback) or
        `decisions:develop` (everything else, including owner feedback and the
        review queue). An operation listing no scope takes any scoped key. A key
        with no scope, or without the operation's, gets 403 INSUFFICIENT_SCOPE.

````

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