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

# Get Catalog Source Document

> Mint a short-lived URL for the original bytes of one cited source document, so a user can check a value against the page it was read from.

## What this is for

A citation names a document, a page, and a rectangle. This endpoint returns the bytes behind it, so
a user can see the paper with the cited passage highlighted instead of taking an extracted number
on trust.

Pass the reference exactly as it appears in `provenance.source_blob_ref` or
`citations.*.source_blob_ref`. It is a content-addressed path (`carrier/class/sha`), and the route
accepts it with the slashes either literal or percent-encoded.

## This grant is separate, and you do not have it yet

Reading a market's numbers and reading a carrier's contract are different acts, so this route is
gated on `catalog:documents:read`, **not** on `catalog:read`. No key carries it by default. Granting
it is an explicit act per key: a key that browses your catalog does not acquire document bytes as a
side effect, and a legacy full-access key is denied here rather than admitted by the compatibility
window that covers other routes.

Two further gates apply after the capability, both server-side and both evaluated against one
database snapshot:

* **Backing.** The reference must back at least one current served row for your organization and
  connection. The servable set is therefore a subset of what you already read, and this route can
  never widen the set of documents your organization knows about. A reference that backs nothing you
  can see returns `404`, which never distinguishes "does not exist" from "belongs to someone else".
* **Document type.** Only carrier paper is servable: agency agreements, commission schedules,
  appetite guides, name changes, and lock-ins. Anything else returns
  `403 document_type_not_servable`. Production reports are excluded because they are your own book
  production rather than carrier paper, and documents nothing has classified are excluded because a
  route must not serve bytes whose sensitivity nothing has judged.

The type is read from the passes that **accepted** the document, not from every pass that looked at
it. A misfiled document can leave a record under a pass that examined it and concluded it was
something else; that record does not lend the document its type.

## Fetch it server-side

```ts theme={null}
// Your server. The API key never reaches the browser.
const res = await fetch(
  `https://api.usenexio.com/api/v1/catalog/documents/${citation.source_blob_ref}`,
  { headers: { Authorization: `Bearer ${process.env.NEXIO_API_KEY}` } },
)
const { source_url, media_type, page_count, expires_in_seconds } = await res.json()
```

`source_url` is a presigned URL scoped to that one object and valid for `expires_in_seconds`
(five minutes). Bytes never pass through the platform API process. Proxy the URL to the browser or
stream it through your own handler; do not ship your API credential to a client in order to fetch
it, and do not persist the URL past its expiry.

`page_count` is `null` when the document's text derivation recorded no page signal, which is normal
for office formats. Paginate by what your viewer renders rather than treating `null` as zero pages.

## When there is no object store

A deployment without a durable object store returns `501 object_store_unconfigured` rather than a
broken URL. Render your citation at its stated grain with the quote as text and no page view.


## OpenAPI

````yaml GET /api/v1/catalog/documents/{source_blob_ref}
openapi: 3.1.0
info:
  title: Nexio API
  version: '1.0'
  description: |
    Nexio agentic infrastructure API. Configure engines for placement,
    entity analysis, and other patterns. Submit runs, poll for results,
    or subscribe to signed webhook callbacks.
  contact:
    email: support@usenexio.com
    url: https://docs.usenexio.com
servers:
  - url: https://api.usenexio.com
    description: Production
security:
  - BearerAuth: []
tags:
  - name: EngineManagement
    description: Create, configure, and manage inference engines.
  - name: Engines
    description: Engine-scoped endpoints for submitting runs and retrieving results.
  - name: Runs
    description: Retrieve and reconcile submitted runs.
  - name: Catalog
    description: >-
      Read current markets and products extracted for the authenticated
      organization.
  - name: Environments
    description: Isolated tenancy scopes under your org (one live plus non-live sandboxes).
  - name: Webhooks
    description: Manage webhook endpoints for push-based delivery of terminal run events.
  - name: Converse
    description: The raw stateless conversational model turn (caller-owned state).
  - name: Conversations
    description: >-
      Conversation instances (orchestrators over engines) and their managed
      conversations, turns, annotations, evals, and exports.
paths:
  /api/v1/catalog/documents/{source_blob_ref}:
    get:
      tags:
        - Catalog
      summary: Get Catalog Source Document
      description: |
        Returns a short-lived presigned URL for the original bytes of one cited
        source document, so a citation can be checked against the page it was
        read from. Bytes never pass through the platform API process.

        Scoped credentials require `catalog:documents:read`. That grant is
        deliberately distinct from `catalog:read` (browsing a market's numbers
        and reading a carrier's contract are different acts), and it is carried
        by no key by default: it is granted per key as an explicit act. Legacy
        broad API keys are denied outright on this route (`scoped_key_required`)
        rather than admitted by the compatibility bypass other routes allow.

        Two further gates apply after the capability, both server-side:

        - **Backing.** The reference must back at least one current served head
          for the caller's organization and connection, so the servable set is a
          subset of what the caller already reads. A reference that backs nothing
          visible returns `404`, which never distinguishes "does not exist" from
          "belongs to another organization".
        - **Document type.** Only carrier-paper types are servable: agency
          agreements, commission schedules, appetite guides, name changes, and
          lock-ins. Anything else returns `403 document_type_not_servable`.

        `source_blob_ref` is the content-addressed path a `provenance` or
        `citation` object carries (`carrier/class/sha`). Pass it unescaped: the
        route accepts the slashes as part of the reference.
      operationId: getCatalogDocument
      parameters:
        - name: source_blob_ref
          in: path
          required: true
          description: >-
            The document's content-addressed reference, exactly as it appears in
            `provenance.source_blob_ref` or `citations.*.source_blob_ref`.
          schema:
            type: string
            maxLength: 500
        - $ref: '#/components/parameters/CatalogConnectionID'
      responses:
        '200':
          description: A short-lived presigned URL for the document's original bytes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogDocumentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            The credential lacks `catalog:documents:read`, is a legacy broad
            key, or the document's type is not servable through this route.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                code: document_type_not_servable
                message: >-
                  This document type is not servable through the catalog
                  document route.
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '501':
          description: >-
            This deployment has no durable object store configured, so original
            documents cannot be served.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                code: object_store_unconfigured
                message: >-
                  document serving requires the object store; not configured for
                  this deployment
        '503':
          $ref: '#/components/responses/AuthUnavailable'
components:
  parameters:
    CatalogConnectionID:
      name: connection_id
      in: query
      description: >
        Pin the browse to one active data connection. Optional when the org has
        a

        single active connection; required when it has more than one (an
        ambiguous

        request returns `catalog_connection_ambiguous`).
      schema:
        type: string
        format: uuid
  schemas:
    CatalogDocumentResponse:
      type: object
      additionalProperties: false
      required:
        - source_url
        - media_type
        - page_count
        - expires_in_seconds
      properties:
        source_url:
          type: string
          description: >-
            A presigned URL scoped to this one object, valid for
            `expires_in_seconds`. Fetch it server-side and proxy to the browser;
            never ship the API credential to a client.
        media_type:
          type: string
          description: >-
            The document's stored media type, which the presign also forces on
            the response.
        page_count:
          type: integer
          nullable: true
          description: >-
            Pages recorded by the document's text derivation. Null when the
            derivation recorded no page signal; a count is never fabricated.
        expires_in_seconds:
          type: integer
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: |
            Stable snake_case error identifier. Safe to match programmatically.

            Known codes: `invalid_request`, `invalid_input`, `unauthorized`,
            `auth_unavailable`, `rate_limited`, `missing_run_id`,
            `invalid_run_id`, `run_not_found`, `invalid_offerings`,
            `missing_input`, `queue_unreachable`,
            `engine_not_found`, `engine_slug_conflict`, `engine_archived`,
            `instance_not_found`, `instance_slug_conflict`, `instance_archived`,
            `instance_follows_canonical`, `instance_not_published`,
            `invalid_engine_type`, `validation_error`,
            `webhook_not_found`, `webhook_limit_exceeded`, `invalid_url`,
            `invalid_events`, `invalid_description`, `invalid_auth_token`,
            `missing_endpoint_id`, `invalid_endpoint_id`, `missing_delivery_id`,
            `invalid_delivery_id`, `delivery_not_found`,
            `delivery_not_resendable`, `insufficient_capability`,
            `engine_version_required`, `engine_version_exact_required`,
            `engine_version_not_found`, `engine_version_invalid_format`,
            `engine_version_draft_requires_sandbox_key`,
            `engine_version_none_released`, `test_scenario_sandbox_only`,
            `test_scenario_forbidden`, `test_scenario_exact_version_required`,
            `test_scenario_version_not_supported`, `invalid_test_scenario`,
            `request_bound_exceeded`, and `run_cap_exceeded`.
        message:
          type: string
          description: Human-readable error message. May change between versions.
        details:
          description: |
            Optional request-specific details. Request-bound failures use the
            `RequestBoundDetails` object. Validation failures may use an array
            of field issues or another documented object.
  responses:
    BadRequest:
      description: Invalid request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalidRequest:
              summary: Malformed JSON
              value:
                code: invalid_request
                message: Request body is not valid JSON
            invalidInput:
              summary: Input validation failed
              value:
                code: invalid_input
                message: Input failed validation
                details:
                  - field: input.address.state
                    message: address.state is required for placement runs.
            invalidOfferings:
              summary: Placement run missing offerings
              value:
                code: invalid_offerings
                message: Inline offerings failed validation
                details:
                  - field: offerings
                    message: >-
                      Offerings are required for placement runs. Pass provider
                      offerings in the top-level offerings array.
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: unauthorized
            message: Missing or invalid API key
    NotFound:
      description: The requested resource does not exist in the authenticated org.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: not_found
            message: Market not found
    RateLimited:
      description: Rate limit exceeded. Retry after the window resets.
      headers:
        Retry-After:
          description: Seconds until the rate limit window resets.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: rate_limited
            message: Rate limit exceeded
    AuthUnavailable:
      description: API key authentication is temporarily unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: auth_unavailable
            message: API key authentication is temporarily unavailable
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: |
        Send the credential as `Authorization: Bearer <key>`.

        Scoped partner credentials use the exclusive `nxsk_v1_...` namespace.
        Each scoped key is bound at issuance to one organization, one canonical
        named environment, an explicit engine set, and a least-privilege
        capability set. A malformed, unknown, rotated, or revoked `nxsk_` key
        fails closed and is never retried as a legacy key.

        Capabilities used by this API are `runs:write`, `runs:read`,
        `engines:read`, `catalog:read`, `webhooks:manage`,
        `runs:defensibility:read`, `runs:test`, `conversations:use`, and
        `conversations:export`. Operation descriptions name the required
        capability.
        Grandfathered `nx_live_...` and `nx_test_...` keys retain their existing
        broad access during the compatibility window.

````