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

# Set Reserves

> Sets the expected total for one `(event, reserved category)` scope — the
`reserves.set` action, an ABSOLUTE "set expected total to X" (never a
delta): the reserve position becomes `X − paid-to-date`. The previous
total and the delta are recorded server-side under the scope's lock —
clients never author them.

`expectedTotalCents` is user display cents — the magnitude a user would
type; the category's `expectedDirection` orients it. Read the scope's
current total with
[entity balances](/api-reference/financials/get-entity-balances).

**X itself is unconstrained.** The only law a reserve scope's amounts
obey is the identity Reserves + Paid = Expected Total, and the identity
holds at every sign. A set below the scope's paid-to-date is a legal,
meaningful state (`200`): the remaining reserve reads NEGATIVE — the
books' honest statement that more has moved than the estimate says the
scope is worth, and the difference is expected to come back (or the
estimate to be corrected later). The server never blocks it.

**No `If-Match`.** Reserve writes serialize on the scope's lock instead
of an invoice watermark.

**Signature preconditions (`422`).** The category must be configured,
reserved, and live (`UNKNOWN_ID` / `NOT_RESERVED_CATEGORY` /
`DEPRECATED_CONFIG` — deprecation blocks new sets, never resets); the
reserve date must not be in the future (`FUTURE_DATE`).

**Idempotency.** `actionId` is a client-minted uuid — an identical retry
replays the original outcome; reuse with a different payload is
`409 ACTION_ID_REUSED`. Setting the same total again with a FRESH
`actionId` is a defined zero-row no-op (journaled, delta 0).

**Required permission:** `company.payment:update`




## OpenAPI

````yaml /openapi/generated-external-api.yaml put /api/v1/companies/{companyId}/financials/events/{eventId}/reserves/{categoryId}
openapi: 3.0.3
info:
  title: AI Insurance External API
  description: External API for AI Insurance platform
  version: 1.0.0
  contact:
    email: support@aiinsurance.io
servers:
  - url: https://go.aiinsurance.io
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/v1/companies/{companyId}/financials/events/{eventId}/reserves/{categoryId}:
    put:
      tags:
        - Financials
      summary: Set Reserves
      description: |
        Sets the expected total for one `(event, reserved category)` scope — the
        `reserves.set` action, an ABSOLUTE "set expected total to X" (never a
        delta): the reserve position becomes `X − paid-to-date`. The previous
        total and the delta are recorded server-side under the scope's lock —
        clients never author them.

        `expectedTotalCents` is user display cents — the magnitude a user would
        type; the category's `expectedDirection` orients it. Read the scope's
        current total with
        [entity balances](/api-reference/financials/get-entity-balances).

        **X itself is unconstrained.** The only law a reserve scope's amounts
        obey is the identity Reserves + Paid = Expected Total, and the identity
        holds at every sign. A set below the scope's paid-to-date is a legal,
        meaningful state (`200`): the remaining reserve reads NEGATIVE — the
        books' honest statement that more has moved than the estimate says the
        scope is worth, and the difference is expected to come back (or the
        estimate to be corrected later). The server never blocks it.

        **No `If-Match`.** Reserve writes serialize on the scope's lock instead
        of an invoice watermark.

        **Signature preconditions (`422`).** The category must be configured,
        reserved, and live (`UNKNOWN_ID` / `NOT_RESERVED_CATEGORY` /
        `DEPRECATED_CONFIG` — deprecation blocks new sets, never resets); the
        reserve date must not be in the future (`FUTURE_DATE`).

        **Idempotency.** `actionId` is a client-minted uuid — an identical retry
        replays the original outcome; reuse with a different payload is
        `409 ACTION_ID_REUSED`. Setting the same total again with a FRESH
        `actionId` is a defined zero-row no-op (journaled, delta 0).

        **Required permission:** `company.payment:update`
      operationId: setFinancialsReserve
      parameters:
        - $ref: '#/components/parameters/companyId'
        - name: eventId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Event identifier — an unknown event is `404`
        - name: categoryId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: >-
            A configured RESERVED transaction category — discover ids with `GET
            /api/v1/companies/{companyId}/financials/config/categories`
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - actionId
                - expectedTotalCents
                - reserveDate
              properties:
                actionId:
                  type: string
                  format: uuid
                  description: >-
                    Client-minted idempotency key — becomes the action's journal
                    id. An identical retry replays the original outcome; reuse
                    with a different payload is `409 ACTION_ID_REUSED`
                author:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: >-
                    Optional display label for the source system's author (e.g.
                    the integrator-side user). Stamped as the journal record's
                    display attribution; the acting principal stays the External
                    API service user, so a label can never impersonate an in-app
                    user. Ignored on idempotent replays
                expectedTotalCents:
                  type: integer
                  description: >-
                    The scope's new ABSOLUTE expected total, in user display
                    cents (never a delta). Unconstrained — a value below the
                    scope's paid-to-date is legal and leaves the remaining
                    reserve negative
                reserveDate:
                  type: string
                  format: date
                  description: >-
                    The reserve date (ISO `YYYY-MM-DD`); must not be in the
                    future
                memo:
                  type: string
                  description: Free-text memo
            examples:
              setReserve:
                summary: Set the expected total to $100.00
                value:
                  actionId: 1e3f5a7b-9c0d-4e2f-4a6b-5c7d8e9f0a1b
                  expectedTotalCents: 10000
                  reserveDate: '2026-06-01'
                  memo: Initial reserve
      responses:
        '200':
          description: The scope's refreshed expected total
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FinancialsV2ReserveWriteResponse'
              examples:
                reserveSet:
                  summary: Reserves set
                  value:
                    journalIds:
                      - 1e3f5a7b-9c0d-4e2f-4a6b-5c7d8e9f0a1b
                    eventId: 550e8400-e29b-41d4-a716-446655440200
                    categoryId: 550e8400-e29b-41d4-a716-446655440101
                    expectedTotalCents: 10000
        '400':
          description: Bad Request — a malformed payload or unknown fields
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingActionId:
                  summary: Missing actionId
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: >-
                        actionId: Invalid input: expected string, received
                        undefined
                      userMessages:
                        - >-
                          actionId: Invalid input: expected string, received
                          undefined
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: >-
            Not Found — no event with this id, or the company does not have this
            financials surface enabled (indistinguishable by design). An unknown
            CATEGORY is `422 UNKNOWN_ID` (cited configuration, not a path
            resource)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                eventNotFound:
                  summary: Event not found
                  value:
                    error:
                      code: NotFoundError
                      message: Event not found
                      userMessages:
                        - Event not found
        '409':
          $ref: '#/components/responses/FinancialsV2ActionIdReused'
        '422':
          $ref: '#/components/responses/FinancialsV2PreconditionFailed'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    companyId:
      name: companyId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Company identifier
  schemas:
    FinancialsV2ReserveWriteResponse:
      type: object
      description: >-
        The response of a reserve write: the emitted journal id(s) plus the
        scope's NEW expected total — the number a `reserves.set` to the same
        value would be a no-op against.
      required:
        - journalIds
        - eventId
        - categoryId
        - expectedTotalCents
      properties:
        journalIds:
          type: array
          minItems: 1
          items:
            type: string
            format: uuid
          description: >-
            Every journal id the action emitted — the `actionId` you supplied
            first, then any companion batch it composed
        eventId:
          type: string
          format: uuid
          description: The scope's event, echoed
        categoryId:
          type: string
          format: uuid
          description: The scope's reserved category, echoed
        expectedTotalCents:
          type: integer
          description: >-
            The scope's expected total AFTER the write, in user display cents
            (the magnitude a user would type; the category's `expectedDirection`
            orients it)
    ErrorResponse:
      type: object
      description: Standard error response for all external API endpoints
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: VALIDATION_ERROR
            message:
              type: string
              description: Human-readable error message
              example: 'submissionId: Required field is missing'
            userMessages:
              type: array
              description: >-
                Clean, verbatim-displayable messages — one entry per failure,
                free of error-code tags, field paths, and internal noise.
                Suitable for showing to end users as-is.
              items:
                type: string
              example:
                - Exposures of type 'company' require an address
            details:
              type: array
              description: Additional details for validation errors (field-level errors)
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: The field that caused the error
                    example: submissionId
                  message:
                    type: string
                    description: Description of the field error
                    example: Required field is missing
    FinancialsV2PreconditionError:
      type: object
      description: >-
        A failed write precondition (`422`): the request was well-formed but the
        books reject it. Preconditions fail closed — a rejected write leaves no
        journal record, no ledger change, and no read-state change. `error.code`
        is one of the STABLE financials error codes (single source:
        `FINANCIALS_V2_PRECONDITION_CODES` in the engine's error module,
        re-exported to this surface as `FINANCIALS_V2_API_ERROR_CODES`) —
        messages may be reworded, the codes will not.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - LIVE_PAYMENTS
                - AMOUNT_EXCEEDS_BALANCE_DUE
                - INVALID_AMOUNT
                - LINE_ITEMS_IMMUTABLE
                - INVOICE_DELETED
                - INVOICE_VOIDED
                - INVOICE_DRAFT
                - INVOICE_NOT_DRAFT
                - PAYMENT_NOT_FOUND
                - ERODE_RESERVES_MISMATCH
                - ERODE_REQUIRES_EVENT
                - DEPRECATED_CONFIG
                - NOT_RESERVED_CATEGORY
                - FUTURE_DATE
                - UNKNOWN_ID
                - LINK_TARGET_MISSING
                - UNAPPROVE_PAID
                - NOT_APPROVED
                - POLICY_INVOICE_BATCH_ONLY
              description: >-
                The stable precondition code — one per guard. `LIVE_PAYMENTS`
                (the action — re-link, payee change, or void — needs the
                invoice's live payments removed first);
                `AMOUNT_EXCEEDS_BALANCE_DUE` (a payment mark's magnitude
                overshoots its line item's remaining — per line, never a
                document scalar); `INVALID_AMOUNT` (a zero mark, or a mark whose
                sign opposes its line item's open remaining — a `payBalanceDue`
                against a document with nothing open included);
                `LINE_ITEMS_IMMUTABLE` (a posted invoice's line items — ids,
                types, amounts — and its category are fixed from the posting
                moment: any post-posting change is rejected, at any payment
                count; corrections are void-and-recreate, payments removed
                first; drafts edit freely until finalize); `INVOICE_DELETED` /
                `INVOICE_VOIDED` (lifecycle closures); `INVOICE_DRAFT` (drafts
                are unposted — money may not touch one: recording a payment on
                or voiding a draft is rejected; finalize it first);
                `INVOICE_NOT_DRAFT` (finalize targets exactly a draft);
                `PAYMENT_NOT_FOUND` (no live payment mark with that id on that
                invoice); `ERODE_RESERVES_MISMATCH` / `ERODE_REQUIRES_EVENT`
                (the erode flag missing on a reserved category or present on
                operating; eroding needs a linked event — there is no headroom
                bound: the remaining reserve is a signed balance and may cross
                zero); `DEPRECATED_CONFIG` / `NOT_RESERVED_CATEGORY` /
                `UNKNOWN_ID` (cited configuration guards); `FUTURE_DATE`;
                `LINK_TARGET_MISSING` (the named link target does not exist);
                `UNAPPROVE_PAID` (an approval cannot be revoked once payments
                have been recorded — remove them first); `NOT_APPROVED` (money
                cannot post against an unapproved invoice AND the calling key
                does not hold `company.payment:approve`, so it cannot approve it
                either — a key that holds the permission auto-approves instead
                of failing here); `POLICY_INVOICE_BATCH_ONLY` (the write touches
                a POLICY-LINKED invoice's document — creating one with
                `links.policy`, or updating, voiding, restoring, deleting, or
                re-linking one that is already policy-linked. A policy's
                invoices are issued as one set so that every price component of
                the policy's pricing contract stays netted to its own line item,
                so they are written only by the policy invoice batch: `POST
                /api/v1/companies/{companyId}/financials/policies/{policyId}/invoices/batch`.
                Change the policy or submit an explicit batch and the invoices
                are reissued. Payments, payee changes, and approvals on a policy
                invoice are unaffected)
            message:
              type: string
              description: Human-readable description of the failed precondition
            userMessages:
              type: array
              description: Clean, verbatim-displayable messages
              items:
                type: string
  responses:
    Unauthorized:
      description: Unauthorized - Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingApiKey:
              summary: Missing API key
              value:
                error:
                  code: AuthenticationError
                  message: API key authentication required
                  userMessages:
                    - API key authentication required
            invalidApiKey:
              summary: >-
                Invalid API key (e.g. unknown key, or a Bearer token used
                instead of an API key)
              value:
                error:
                  code: AuthenticationError
                  message: Invalid API key
                  userMessages:
                    - Invalid API key
    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficientPermissions:
              summary: Insufficient permissions
              value:
                error:
                  code: AuthorizationError
                  message: User is not authorized to perform the requested action
                  userMessages:
                    - User is not authorized to perform the requested action
            companyMismatch:
              summary: A valid API key naming another company in the URL
              value:
                error:
                  code: AuthorizationError
                  message: API key is not scoped to the requested company
                  userMessages:
                    - API key is not scoped to the requested company
    FinancialsV2ActionIdReused:
      description: >-
        Conflict — the `actionId` was already used by a DIFFERENT action
        (different action type, target, or client payload). Supply a fresh uuid.
        An IDENTICAL retry never conflicts: it replays the original outcome
        (`200`) instead.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            actionIdReused:
              summary: actionId reused by a different action
              value:
                error:
                  code: ACTION_ID_REUSED
                  message: >-
                    actionId 550e8400-e29b-41d4-a716-446655440000 was already
                    used by a different action; supply a fresh uuid (or retry
                    with the identical action to replay it)
                  userMessages:
                    - >-
                      actionId 550e8400-e29b-41d4-a716-446655440000 was already
                      used by a different action; supply a fresh uuid (or retry
                      with the identical action to replay it)
    FinancialsV2PreconditionFailed:
      description: >-
        Unprocessable — a write precondition failed. Fails closed: no journal
        record, no ledger change, no read-state change. `error.code` is one of
        the stable financials error codes; each operation's description names
        its signature codes.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/FinancialsV2PreconditionError'
          examples:
            livePayments:
              summary: The action requires the invoice's live payments removed first
              value:
                error:
                  code: LIVE_PAYMENTS
                  message: >-
                    The invoice has live payments; remove them before this
                    action
                  userMessages:
                    - >-
                      The invoice has live payments; remove them before this
                      action
            unknownId:
              summary: >-
                A cited configuration id is unknown (or outside the cited
                category)
              value:
                error:
                  code: UNKNOWN_ID
                  message: lineItemTypeId does not belong to the cited category
                  userMessages:
                    - lineItemTypeId does not belong to the cited category
            policyInvoiceBatchOnly:
              summary: >-
                Policy-linked invoice documents are changed only as one policy
                batch
              value:
                error:
                  code: POLICY_INVOICE_BATCH_ONLY
                  message: >-
                    Policy-linked invoice documents can only be changed through
                    POST
                    /api/v1/companies/{companyId}/financials/policies/{policyId}/invoices/batch
                  userMessages:
                    - >-
                      Policy-linked invoice documents can only be changed
                      through POST
                      /api/v1/companies/{companyId}/financials/policies/{policyId}/invoices/batch
    InternalServerError:
      description: Internal Server Error - Unexpected error occurred
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            internalError:
              summary: Unexpected server error
              value:
                error:
                  code: UncaughtActionError
                  message: Uncaught error occurred in <actionName>
                  userMessages:
                    - An unexpected error occurred. Please try again later.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        API key authentication. Send your raw API key as the `Authorization`
        header value with NO scheme prefix — `Authorization: YOUR-API-KEY`. Do
        NOT prefix it with `Bearer ` or `ApiKey `, and do not use an `X-API-Key`
        header; those are not accepted.

````