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

# Track credit consumption

> Records usage and charges credit for it. The request carries no credit amount: send what happened, and the response's `charges` carry what it priced to per metric, with `totals` as the sum.

Two shapes. A direct draw (`account` + `events`) charges against the account's current credit. A settlement (`reservation_id` + `events` + `close`) closes a hold opened by `/beta/credits/check`, pricing each metric at the rate frozen when the hold opened. One payload can feed several credit-consuming metrics, and the draw is all-or-nothing: a refusal for one metric leaves every metric uncharged.

Events sent here are both metered and charged, so do not also send them to `POST /beta/events`. An event feeding no credit-consuming metric is rejected with `422` and belongs there instead. Identity comes from the `Idempotency-Key`, or from the events' own `unique_id`s when no key is sent; reuse it when retrying. Insufficient credit returns `200` with `allowed: false`. `409` means the identity is bound to different work. Back off on `429`.



## OpenAPI

````yaml /api-reference/v2/specs/2026-04-01.json post /credits/track
openapi: 3.1.0
info:
  title: Alguna Public API
  version: '2026-04-01'
servers:
  - url: https://api.alguna.io
security:
  - bearerAuth: []
tags:
  - name: Billing Events and Metrics
  - name: Checkout Sessions
  - name: Credit Notes
  - name: Credits
  - name: Customer Portal Sessions
  - name: Customers
  - name: Insights
  - name: Integrations
  - name: Invoices
  - name: Payments
  - name: Plans
  - name: Product Bundles
  - name: Products
  - name: Refunds
  - name: Revenue Schedules
  - name: Subscription Changes
  - name: Subscription Versions
  - name: Subscriptions
  - name: Tax
  - name: Wallet Grants
  - name: Wallets
paths:
  /credits/track:
    post:
      tags:
        - Credits
      summary: Track credit consumption
      description: >-
        Records usage and charges credit for it. The request carries no credit
        amount: send what happened, and the response's `charges` carry what it
        priced to per metric, with `totals` as the sum.


        Two shapes. A direct draw (`account` + `events`) charges against the
        account's current credit. A settlement (`reservation_id` + `events` +
        `close`) closes a hold opened by `/beta/credits/check`, pricing each
        metric at the rate frozen when the hold opened. One payload can feed
        several credit-consuming metrics, and the draw is all-or-nothing: a
        refusal for one metric leaves every metric uncharged.


        Events sent here are both metered and charged, so do not also send them
        to `POST /beta/events`. An event feeding no credit-consuming metric is
        rejected with `422` and belongs there instead. Identity comes from the
        `Idempotency-Key`, or from the events' own `unique_id`s when no key is
        sent; reuse it when retrying. Insufficient credit returns `200` with
        `allowed: false`. `409` means the identity is bound to different work.
        Back off on `429`.
      operationId: track-credits
      parameters:
        - in: header
          name: Alguna-Version
          required: true
          schema:
            enum:
              - '2026-04-01'
            type: string
        - in: header
          name: Idempotency-Key
          schema:
            description: >-
              A unique string used to ensure the request is processed exactly
              once. If you retry a request with the same idempotency key within
              24 hours, the original response is returned without re-executing
              the operation.
            example: ik_a1b2c3d4e5f6
            maxLength: 255
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrackCreditsRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackCreditsResponse'
          description: Success
          headers:
            Idempotency-Key:
              description: Echo of the idempotency key provided in the request
              schema:
                type: string
            Idempotent-Replayed:
              description: >-
                Whether this response was replayed from a previous request
                (true) or freshly executed (false)
              schema:
                type: boolean
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Bad Request
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Not Found
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            Conflict — a request with this idempotency key is currently being
            processed
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Unprocessable Entity
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Internal Server Error
components:
  schemas:
    TrackCreditsRequest:
      properties:
        account:
          description: >-
            Customer account ID or alias; direct-draw mode. Required unless
            reservation_id is set, where the account comes from the reservation.
          example: cust_abc123
          nullable: true
          type: string
        close:
          description: >-
            Whether this is the final call for the reservation. Required
            whenever reservation_id is set: there is no safe default, since true
            would end runs that meant to continue and false would leak
            reservations until they expire. The reservation also closes on its
            own if the events consume everything held. Not valid on a direct
            draw.
          example: true
          nullable: true
          type: boolean
        events:
          description: >-
            The usage being recorded, up to 100 events. The amount charged is
            computed from these against whichever billable metrics count them;
            there is no credit amount in the request. On a settlement, an empty
            array with close: true releases the whole reservation, charging
            nothing, which is the recovery when work is abandoned.
          items:
            $ref: '#/components/schemas/TrackCreditEvent'
          type: array
        on_envelope_exceeded:
          description: >-
            What to do when a settle cannot be fully covered by credit on a
            metric that stops at zero — either because it prices past the
            reservation's authorized hold, or because credit ran out before a
            late settle arrived. "reject" (the default) refuses the settle,
            burning and recording nothing. "record" burns what is available and
            reports the remainder in the charges' overflow, deliberately
            weakening a hard stop you configured. Reservation-settlement mode
            only. The refusal body's reason says which condition fired: adding
            credit resolves coverage_shortfall, but not envelope_exceeded, whose
            limit is the hold's size.
          enum:
            - reject
            - record
          example: record
          nullable: true
          type: string
        reservation_id:
          description: >-
            Reservation token returned by /check, to close it;
            reservation-settlement mode. Mutually exclusive with account. The
            events sent alongside are both metered and charged, so do not send
            them to /events as well.
          example: crt_abc123
          nullable: true
          type: string
      required:
        - events
      type: object
    TrackCreditsResponse:
      properties:
        allowed:
          description: Whether the consumption was covered by available credit
          type: boolean
        at_zero_action:
          description: >-
            The reservation's at-zero policy, reported when the envelope was
            exceeded.
          example: stop
          type: string
        balances:
          description: >-
            Per-metric, per-ledger availability after this call — one entry per
            ledger, so a single-ledger payload returns one. Always an array, but
            empty when no availability was resolved to report, including every
            response served while the organization's gate is disabled. Check the
            length before indexing.
          items:
            $ref: '#/components/schemas/CreditBalance'
          type: array
        charges:
          description: >-
            One entry per metric this call's events fed: quantity counted,
            credits priced, credit covered, overflow to cash, and the ledger
            that paid. Always an array, length 1 in the ordinary single-metric
            case.
          items:
            $ref: '#/components/schemas/CreditCharge'
          type: array
        envelope_exceeded:
          description: >-
            True when the events priced past the reservation's remaining hold
            and were recorded anyway because on_envelope_exceeded was record.
            Worth alarming on for a feature that stops at zero.
          type: boolean
        events_accepted:
          description: How many events this call recorded.
          example: 3
          format: int64
          type: integer
        events_priced:
          description: >-
            How many of those events at least one metric's filters counted
            toward a charge. A lower number than events_accepted means some
            events did not qualify, without exposing the filter itself.
          example: 2
          format: int64
          type: integer
        reservation_expired:
          description: >-
            True when the referenced reservation had expired and the work was
            re-resolved as a fresh consume
          type: boolean
        reservation_expires_at:
          description: >-
            When the still-open reservation now expires. Each accepted call
            extends this, so a long run that reports as it goes never expires
            mid-flight. Absent once the reservation closes.
          example: '2026-04-01T10:20:00Z'
          format: date-time
          nullable: true
          type: string
        reservation_id:
          description: >-
            Reservation this call settled or opened. Empty for a
            direct-consumption draw that opened no block.
          example: crt_abc123
          type: string
        reservation_open:
          description: >-
            Whether the reservation is still open and can be settled again.
            False even on a close: false call whose events consumed everything
            held — there is no envelope left to keep open.
          type: boolean
        reservation_remaining:
          description: Credits still held by this reservation and available to later calls.
          example: '0'
          type: string
        totals:
          allOf:
            - $ref: '#/components/schemas/CreditTotals'
          description: >-
            The charges summed. Derived from charges — the breakdown is
            authoritative.
      required:
        - allowed
        - balances
        - charges
        - reservation_id
        - reservation_open
        - reservation_remaining
        - totals
      type: object
    ErrorResponse:
      properties:
        detail:
          type: string
        status:
          format: int64
          type: integer
      required:
        - status
        - detail
      type: object
    TrackCreditEvent:
      properties:
        event_name:
          description: >-
            Usage event name. On a settlement it must be counted by one of the
            metrics the reservation covers, or the request is rejected.
          example: agent_step
          type: string
        properties:
          description: >-
            Event properties. For a metric that sums a property, the aggregation
            field is required here and is the billing input for this event.
          type: object
        timestamp:
          description: When the usage happened (RFC3339). Defaults to receipt time.
          example: '2026-04-01T10:00:00Z'
          format: date-time
          nullable: true
          type: string
        unique_id:
          description: >-
            Stable dedupe identity for this event, max 72 characters. Must be
            unique within the payload; reuse the same identity on every retry.
          example: run_88f_step1
          maxLength: 72
          type: string
      required:
        - event_name
        - unique_id
      type: object
    CreditBalance:
      properties:
        available:
          description: >-
            What these metrics can still spend from this ledger. When filtered
            is true this is the eligible grant balances net of open holds;
            otherwise it is the plain ledger figure.
          example: '985'
          type: string
        credit_type:
          description: The credit denomination of this entry.
          example: units
          type: string
        filtered:
          description: >-
            True when available reflects the resolved eligible grants net of
            open holds. False when no plan was resolved for this entry (a
            replay, a rate-limit shed, a settlement against a hold, or a
            degraded availability read) and available is the plain ledger
            figure.
          type: boolean
        ledger_id:
          description: >-
            The credit ledger this availability sits on. Omitted when there is
            no wallet to name: no plan was resolved for the entry (a replay, a
            rate-limit shed), no matching grant exists — none was ever made, or
            every one has expired or been voided — or the ledger read behind a
            degraded entry also failed. A merely drained wallet keeps its id, so
            balances[0].ledger_id still answers at the moment credit runs out.
          example: crl_abc
          type: string
        metric_ids:
          description: >-
            The billable metrics this availability applies to. One metric's
            credit can span several ledgers, so sum its entries to reconstruct
            its spendability; two metrics with identical availability share one
            entry.
          example:
            - '["mtr_1"]'
          items:
            type: string
          type: array
        scope:
          allOf:
            - $ref: '#/components/schemas/CreditBalanceScope'
          description: >-
            The scope the entry was resolved under. Omitted when the outcome was
            answered before any plan was resolved (a rate-limit shed) or against
            a hold's own ledgers (a settlement).
          nullable: true
      required:
        - available
        - credit_type
        - filtered
        - metric_ids
      type: object
    CreditCharge:
      properties:
        covered:
          description: >-
            The part of credits that credit covered — drawn on a /track, fenced
            by the hold on a /check with reserve, zero on a quote or preflight
            where nothing moves.
          example: '15'
          type: string
        credits:
          description: What that quantity priced to in credits, at this metric's rate.
          example: '15'
          type: string
        ledger_id:
          description: >-
            The credit ledger the covered part drew from. Empty when nothing was
            covered, and for a metric that consumes no credit. A charge
            cascading across ledgers names the primary (first-drawn) ledger;
            balances carries the per-ledger availability. On an idempotent
            resend of a settle (a replay), per-metric attribution is not
            reconstructable from the recorded close, so every charge names the
            hold's primary ledger — reconcile per-ledger figures from the first
            response, not a replay.
          example: crl_acct
          type: string
        metric_id:
          description: The billable metric this charge counts against.
          example: mtr_tokens
          type: string
        overflow:
          description: >-
            credits − covered: the part billing as cash, in credits. It is an
            exposure figure, not a record of movement — on a quote, a denied
            reserve, or a degraded fail-open nothing moves and covered is zero,
            so this carries the full credits amount: what the work would bill as
            cash if no credit paid for it.
          example: '0'
          type: string
        quantity:
          description: Metric units this call counted for this metric.
          example: '1500'
          type: string
        uncovered_quantity:
          description: >-
            overflow converted back into metric units — the denomination the
            invoice bills them in. For a metric that consumes no credit, the
            full quantity.
          example: '0'
          type: string
      required:
        - covered
        - credits
        - ledger_id
        - metric_id
        - overflow
        - quantity
        - uncovered_quantity
      type: object
    CreditTotals:
      properties:
        covered:
          description: >-
            Credits actually covered (drawn or held), summed across every
            charge.
          example: '23'
          type: string
        overflow:
          description: >-
            Credits not covered that bill as cash, summed across every charge.
            Where nothing was covered — a quote, a denied reserve, a degraded
            fail-open — this equals used: the cash exposure of the described
            work if no credit pays for it.
          example: '0'
          type: string
        uncovered_metric_quantity:
          description: >-
            Metric units that no realtime credit covered and which therefore
            bill as cash, summed across every charge — each converted at its own
            metric's rate. Invoice-time credits may still apply to them.
          example: '0'
          type: string
        used:
          description: >-
            Credits the call priced to, summed across every charge. Computed
            from the events — never supplied by the caller.
          example: '23'
          type: string
      required:
        - covered
        - overflow
        - uncovered_metric_quantity
        - used
      type: object
    CreditBalanceScope:
      properties:
        filters:
          description: >-
            Reserved. A grant's product/price filters are applied when credits
            are applied to an invoice, not by the gate, so this is never set.
          type: object
        level:
          description: >-
            The level this availability was resolved at. Always account: credit
            is resolved across every grant the account holds. A grant made under
            a subscription still funds realtime draws — its subscription records
            where it came from, and does not narrow what it can pay for — so the
            ledger named by an entry may belong to a subscription even though
            the scope is the account.
          enum:
            - account
          example: account
          type: string
        subscription_id:
          description: >-
            Reserved. Availability is never scoped to a subscription, so this is
            never set.
          example: sub_123
          nullable: true
          type: string
      required:
        - level
      type: object
  securitySchemes:
    bearerAuth:
      bearerFormat: API Key
      description: API key authentication. Pass your API key as a Bearer token.
      scheme: bearer
      type: http

````