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

# Enqueue over HTTP.

> River supports polyglot insertion, and apalis-board's only mutation is enqueue —
yet the first draft of this spec had no way to enqueue at all. This is how a
Python or TypeScript service submits work without a native client, and how an
operator re-submits a repaired payload. Requires Idempotency-Key: a retried POST
must not create a second job.

An embedding application may install ordered enqueue middleware. The first
registered component is outermost; it may mutate an owned envelope copy or veto
before authorization/store I/O, and terminal errors unwind in reverse order.
Direct enqueue and manual periodic run use the same configured chain.

An embedding application may install a per-kind EnqueueAuthorizer. Authentication
happens upstream and supplies an established identity; headgate never trusts an
identity header. The backward-compatible default is allow-all. A policy rejection
happens before store I/O and returns the structured 403 below.

An optional process-local availability circuit is evaluated after authorization.
It counts only typed store-unavailable results; backpressure and other policy
responses prove the store is reachable. An open or probe-saturated circuit does
no store I/O and returns the structured 503 below.

Embedders may also install non-wrapping insert hooks. After authorization and a
circuit permit, each actual store attempt emits one begin and one end event in
registration order, including duplicate and id-conflict results. Middleware
retries create one hook lifecycle per store attempt; pre-store vetoes create none.




## OpenAPI

````yaml /api/headgate.openapi.yaml post /jobs
openapi: 3.1.0
info:
  title: headgate control API
  version: 0.1.0
  description: >
    The web UI is one client of this control API and gets no

    privileged access — asynqmon reads Redis directly, which is why its
    compatibility

    note is three minor versions stale.


    Both the Go and Rust implementations serve this spec, and the conformance
    suite

    asserts identical responses. Every list endpoint is bounded to prevent
    inspection

    from becoming an unbounded store operation: asynq's

    GetQueueInfo is O(number of groups) and has pinned Redis CPU for seconds in

    production. Monitoring caused the outage.


    DERIVED FROM THE ARCHITECTURE, NOT FROM A PREDECESSOR'S UI. The first draft
    of this

    spec was the asynq Inspector surface -- list by state, act on one job, pause
    a queue

    -- with new nouns bolted on. That inherited three problems: it omitted bulk

    operations, history, and enqueue (which asynq and apalis-board respectively
    DO have),

    and more importantly it had no endpoint for the question this system's own
    design

    creates. When dequeue is an admission decision, the operator's first
    question is not

    "what is in the queue" but "why is THIS job not running" -- see
    /jobs/{id}/admission.

    No predecessor needs that endpoint because no predecessor has a gate.
servers:
  - url: /api/v1
security: []
paths:
  /jobs:
    post:
      summary: Enqueue over HTTP.
      description: >
        River supports polyglot insertion, and apalis-board's only mutation is
        enqueue —

        yet the first draft of this spec had no way to enqueue at all. This is
        how a

        Python or TypeScript service submits work without a native client, and
        how an

        operator re-submits a repaired payload. Requires Idempotency-Key: a
        retried POST

        must not create a second job.


        An embedding application may install ordered enqueue middleware. The
        first

        registered component is outermost; it may mutate an owned envelope copy
        or veto

        before authorization/store I/O, and terminal errors unwind in reverse
        order.

        Direct enqueue and manual periodic run use the same configured chain.


        An embedding application may install a per-kind EnqueueAuthorizer.
        Authentication

        happens upstream and supplies an established identity; headgate never
        trusts an

        identity header. The backward-compatible default is allow-all. A policy
        rejection

        happens before store I/O and returns the structured 403 below.


        An optional process-local availability circuit is evaluated after
        authorization.

        It counts only typed store-unavailable results; backpressure and other
        policy

        responses prove the store is reachable. An open or probe-saturated
        circuit does

        no store I/O and returns the structured 503 below.


        Embedders may also install non-wrapping insert hooks. After
        authorization and a

        circuit permit, each actual store attempt emits one begin and one end
        event in

        registration order, including duplicate and id-conflict results.
        Middleware

        retries create one hook lifecycle per store attempt; pre-store vetoes
        create none.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - kind
                - payload
              properties:
                kind:
                  type: string
                schema_version:
                  type: integer
                  default: 1
                payload:
                  type: string
                  contentEncoding: base64
                queue:
                  type: string
                  default: default
                priority:
                  type: integer
                partition_key:
                  type: string
                rate_class:
                  type: string
                weight:
                  type: integer
                  minimum: 1
                  default: 1
                  description: >-
                    Estimated rate-budget cost; unrelated to queue-selection
                    weight.
                scheduled_at_ms:
                  type: integer
                unique_key:
                  type: string
                  contentEncoding: base64
                unique_window_ms:
                  type: integer
                  minimum: 0
                unique_debounce_ms:
                  type: integer
                  minimum: 0
                  description: >-
                    Trailing-edge coalescing window measured from store time;
                    replaces payload and tags on conflict.
                unique_exclude_kind:
                  type: boolean
                  default: false
                  description: >-
                    Use a fleet-global uniqueness namespace instead of the
                    default kind-scoped namespace.
                tags:
                  type: array
                  maxItems: 32
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                pending:
                  type: boolean
                  default: false
                  description: Insert durably but keep ineligible until operator promotion.
                sticky_worker:
                  type: string
                  maxLength: 255
                  description: >-
                    Exact stable worker identity allowed to claim the job; empty
                    means any worker.
                unique_replace:
                  type: integer
                  minimum: 0
                  maximum: 15
                  description: >-
                    Bitmask allowlist for replacing an existing non-running
                    unique holder — payload bundle=1, scheduled_at_ms=2,
                    priority=4, max_attempts=8.
      responses:
        '201':
          description: Enqueued
        '403':
          description: Enqueue authorizer rejected this job kind before store I/O
        '409':
          description: >-
            Duplicate unique key. Body carries the existing job ID and whether
            an allowlisted replacement was applied.
        '423':
          description: The job fingerprint is quarantined.
        '503':
          description: >-
            Store unavailable, or local enqueue circuit open/half-open probe
            budget occupied. Circuit body carries state and retry_after_ms.
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
      description: >
        Required on every mutating request. A double-clicked Retry, or a proxy
        retrying a

        POST, must not enqueue the job twice. Keys are retained long enough to
        cover a

        client retry window and the response is replayed verbatim.

````