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

# Pull entitled events

> Fetches a page of a pull subscription's entitled events in arrival-order `seq`. The read doubles as the acknowledgment (cursor-as-ack): after a successful fetch the highest returned `seq` is persisted as the subscription's cursor, monotonically. An explicit `after` cursor overrides the persisted cursor for the read; a forward seek advances the durable cursor past the unread gap (the skipped range is not re-delivered — caller-owns-the-gap), while a backward seek never rewinds it. The read is rate-limited per tenant. Events are at-least-once; deduplicate on `ceId`.



## OpenAPI

````yaml en/openapi/v3-current/streaming-hub.yaml get /v1/events
openapi: 3.1.0
info:
  title: Lerian Streaming Hub API
  version: v1.0.0
  contact:
    email: contact@lerian.studio
    name: Lerian Studio
    url: https://lerian.studio
  license:
    name: Lerian Studio General License
  description: >-
    The Streaming Hub control-plane API. Streaming Hub is Lerian's managed
    event-delivery edge: it consumes CloudEvents from the platform's internal
    streaming backbone and fans them out to a tenant's own external destinations
    — webhooks, Amazon SQS, RabbitMQ, Amazon EventBridge, or a pull inbox. This
    API lets a tenant browse the manifest-fed event catalog, create and manage
    delivery subscriptions, verify and rotate their credentials, read delivery
    health, and pull entitled events.


    Errors use a flat `{"error":"<token>"}` envelope (a low-cardinality,
    machine-readable token — never RFC 9457 problem+json). Mutating operations
    require an `X-Idempotency` header for at-most-once semantics; a replayed
    request returns the original response byte-for-byte with
    `X-Idempotency-Replayed: true`. The catalog and the pull events surface are
    tenant-scoped through the bearer JWT; the operational probe endpoints
    (`/healthz`, `/readyz`, `/version`, `/runtime`, `/metrics`) are
    unauthenticated. Streaming Hub is closed source under the Lerian Studio
    General License.
servers:
  - url: https://streaming-hub.sandbox.lerian.net
security:
  - BearerAuth: []
tags:
  - name: Catalog
    description: Browse the manifest-fed catalog of event types available for subscription.
  - name: Subscriptions
    description: >-
      Create, read, update, and delete delivery subscriptions, and drive the
      destination verification lifecycle (ping, verify, credential, delegated
      grant, secret rotation, health).
  - name: Event Delivery
    description: >-
      Pull entitled events for a pull-sink subscription
      (cursor-as-acknowledgment read).
  - name: Admin
    description: Cross-tenant operator forensics. Requires an operator authorization scope.
  - name: Operational
    description: Unauthenticated liveness, readiness, build, runtime, and metrics probes.
paths:
  /v1/events:
    get:
      tags:
        - Event Delivery
      summary: Pull entitled events
      description: >-
        Fetches a page of a pull subscription's entitled events in arrival-order
        `seq`. The read doubles as the acknowledgment (cursor-as-ack): after a
        successful fetch the highest returned `seq` is persisted as the
        subscription's cursor, monotonically. An explicit `after` cursor
        overrides the persisted cursor for the read; a forward seek advances the
        durable cursor past the unread gap (the skipped range is not
        re-delivered — caller-owns-the-gap), while a backward seek never rewinds
        it. The read is rate-limited per tenant. Events are at-least-once;
        deduplicate on `ceId`.
      operationId: pullEvents
      parameters:
        - name: subscription_id
          in: query
          required: true
          description: >-
            The pull subscription to read. Resolved through an existence gate
            then a kind gate: an absent, cross-tenant, or non-`pull` id all
            return a uniform `404 not_found` (no existence or kind oracle).
          schema:
            type: string
            format: uuid
        - name: after
          in: query
          required: false
          description: >-
            Explicit keyset cursor (replay). When present it overrides the
            persisted cursor for the read; absent it, the read resumes from the
            persisted acknowledged `seq` (0 = from the beginning). A malformed
            value is ignored and folds to the persisted cursor.
          schema:
            type: integer
            format: int64
        - name: limit
          in: query
          required: false
          description: Page size, clamped to the range 1–500, defaulting to 100.
          schema:
            type: integer
      responses:
        '200':
          description: A page of events in ascending `seq` order.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PullEventsResponse'
        '400':
          description: >-
            The required `subscription_id` query parameter is missing — `error`
            is `bad_request`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          description: >-
            The per-tenant inbound read throttle denied the request — `error` is
            `rate_limited`. Back off and retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - BearerAuth: []
components:
  schemas:
    PullEventsResponse:
      type: object
      additionalProperties: false
      properties:
        events:
          type: array
          description: A page of events in ascending `seq` order.
          items:
            $ref: '#/components/schemas/PullEvent'
        next_cursor:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            The maximum `seq` in the page when it filled exactly to `limit` (a
            possible next page); `null` on a short or final page. This diverges
            deliberately from the subscriptions list cursor (which is a
            DESC-by-id string with an empty-string sentinel).
          examples:
            - 42
      required:
        - events
        - next_cursor
    Error:
      type: object
      additionalProperties: false
      description: >-
        The flat error envelope used across the `/v1` and `/admin` surfaces. It
        carries a single low-cardinality, machine-readable token and never leaks
        secret material or internal detail. (A `403` from the authorization
        decision point is the one exception — its body is plain text.)
      properties:
        error:
          type: string
          description: The machine-readable error token.
          examples:
            - not_found
      required:
        - error
    PullEvent:
      type: object
      additionalProperties: false
      properties:
        seq:
          type: integer
          format: int64
          description: The tenant arrival-order sequence number (the keyset key).
          examples:
            - 42
        ceId:
          type: string
          description: >-
            The CloudEvents id (UUIDv7) — the stable dedup key. Deduplicate on
            this across at-least-once redeliveries.
          examples:
            - 0192f1a0-0000-7000-8000-0000000000ce
        eventType:
          type: string
          description: The event type (the `<resource>.<event>` tail).
          examples:
            - orders.created
        schemaVersion:
          type: string
          description: The event's schema version.
          examples:
            - 1.0.0
        receivedAt:
          type: string
          format: date-time
          description: When the hub received the event (UTC, RFC 3339).
          examples:
            - '2026-06-06T12:00:00Z'
        payload:
          type: object
          additionalProperties: true
          description: >-
            The producer's event payload, surfaced opaquely (arbitrary JSON).
            Carries no secret material.
          examples:
            - order_id: abc
              amount: 42
      required:
        - seq
        - ceId
        - eventType
        - schemaVersion
        - receivedAt
        - payload
  responses:
    Unauthorized:
      description: >-
        Authentication failed, or there is no trusted tenant context. `error` is
        `unauthorized` (uniform body — no reason is leaked).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        The authorization decision point denied the request. The body is plain
        text (not the JSON error envelope).
      content:
        text/plain:
          schema:
            type: string
    NotFound:
      description: >-
        The resource is absent, soft-deleted, or owned by another tenant — a
        uniform `error` of `not_found` (no existence oracle).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: >-
        An infrastructure fault. `error` is `internal_error` (sanitized; detail
        is logged, never returned).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        A bearer JWT issued by plugin-auth (lib-auth). The tenant identity is
        resolved from the validated token claims; the `/v1` surface never reads
        a tenant from the body, path, or query. Machine callers obtain a token
        via the plugin-auth client-credentials flow. The `/admin` surface
        authorizes against an operator scope and carries no tenant context.

````