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

# Preflight signed result files

> Returns single-object signed GET capabilities for raw stored result objects only, never decoded inner chunks or prefix access. All paths must pass the same organization, sample, readiness and delivered-marker gates as batch reads. Only zarr.json, _marker_frame.json, he/ and delivered markers/ paths are accepted. Duplicate paths are deduplicated in first-requested order. At most 16 paths, 64 MiB per object and 64 MiB total; all authorization, metadata and budget checks precede signing. The server fixes a common expiry no later than 120 seconds after preflight; provider credential expiry or object deletion can make a capability unusable sooner. URLs are replayable bearer secrets until effective expiry, not single-use or application-revocable. Changing API access does not revoke an issued URL. Direct storage reads incur provider requests/egress and bypass application read-byte accounting. No client storage credentials are required. A signed whole-object URL does not restrict the recipient to a Range. objectId is SHA-256 of compact UTF-8 JSON [provider,bucket,canonicalKey,version], an identity hash, NOT a content checksum. Checksums are provider base64 when available; ETag is opaque.

Returns short-lived, version-pinned links for whole stored result objects. This
is not an inner-chunk or byte-range endpoint. The existing authenticated result
proxy remains available.

The server validates ownership, marker delivery, all object metadata and the
64 MiB total before signing any link. A request accepts 1 to 16 paths, including
duplicates, and returns deduplicated files in first-requested order. Any failure
rejects the whole manifest. The expiry is fixed at 120 seconds.

> [!WARNING]
>
> URLs are bearer capabilities. Keep the response in memory; do not save it to
> request/response logs, notebooks, receipts or exception bodies. Record only
> byte counts, hashes and URL-free metadata. Never send Strand credentials or
> cookies to the storage provider, and do not follow redirects.

`objectId` fingerprints the provider/bucket/key/version identity. Consumers
must verify the pinned generation/version, exact length and available full-object
MD5/CRC32C checksums. ETags are opaque and are not SHA-256 or necessarily MD5.

The Python SDK exposes complete preflight through `JobResults.get_signed_files()`
and direct reads through `get_files_batch(..., transport="signed")`. MCP's
`download_results` export workflow is unchanged; this endpoint does not add a
URL-printing MCP tool.


## OpenAPI

````yaml POST /jobs/{id}/results/files/signed
openapi: 3.1.0
info:
  title: Strand AI Platform API
  version: v1
  description: >-
    REST surface for uploading WSIs, submitting Lattice inference jobs, and
    streaming results. All endpoints require an API key or Strand AI OAuth
    access token in the `Authorization: Bearer` header.
servers:
  - url: https://app.strandai.com/api/v1
    description: Production
security:
  - ApiKey: []
  - OAuth2: []
paths:
  /jobs/{id}/results/files/signed:
    post:
      summary: Issue version-pinned whole-object result reads
      description: >-
        Returns single-object signed GET capabilities for raw stored result
        objects only, never decoded inner chunks or prefix access. All paths
        must pass the same organization, sample, readiness and delivered-marker
        gates as batch reads. Only zarr.json, _marker_frame.json, he/ and
        delivered markers/ paths are accepted. Duplicate paths are deduplicated
        in first-requested order. At most 16 paths, 64 MiB per object and 64 MiB
        total; all authorization, metadata and budget checks precede signing.
        The server fixes a common expiry no later than 120 seconds after
        preflight; provider credential expiry or object deletion can make a
        capability unusable sooner. URLs are replayable bearer secrets until
        effective expiry, not single-use or application-revocable. Changing API
        access does not revoke an issued URL. Direct storage reads incur
        provider requests/egress and bypass application read-byte accounting. No
        client storage credentials are required. A signed whole-object URL does
        not restrict the recipient to a Range. objectId is SHA-256 of compact
        UTF-8 JSON [provider,bucket,canonicalKey,version], an identity hash, NOT
        a content checksum. Checksums are provider base64 when available; ETag
        is opaque.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - paths
              properties:
                paths:
                  type: array
                  minItems: 1
                  maxItems: 16
                  items:
                    type: string
                    minLength: 1
                    maxLength: 512
      responses:
        '200':
          description: >-
            Private, no-store whole-object capability manifest. All entries have
            the same conservative expiry.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required:
                  - schemaVersion
                  - layout
                  - expiresAt
                  - files
                properties:
                  schemaVersion:
                    type: integer
                    enum:
                      - 1
                  layout:
                    type: string
                    enum:
                      - raw
                  expiresAt:
                    type: string
                    format: date-time
                  files:
                    type: array
                    minItems: 1
                    maxItems: 16
                    items:
                      type: object
                      additionalProperties: false
                      required:
                        - path
                        - provider
                        - objectId
                        - version
                        - sizeBytes
                        - etag
                        - crc32c
                        - md5
                        - expiresAt
                        - url
                      properties:
                        path:
                          type: string
                          minLength: 1
                          maxLength: 512
                        provider:
                          type: string
                          enum:
                            - gcs
                            - s3
                        objectId:
                          type: string
                          pattern: ^[0-9a-f]{64}$
                        version:
                          type: string
                          minLength: 1
                          maxLength: 1024
                          description: >-
                            GCS generation or non-null S3 VersionId. Never an
                            unversioned latest read.
                        sizeBytes:
                          type: integer
                          minimum: 0
                          maximum: 67108864
                        etag:
                          type: string
                          nullable: true
                          maxLength: 1024
                        crc32c:
                          type: string
                          nullable: true
                          description: >-
                            Base64-encoded 4-byte CRC32C, when returned by the
                            provider without additional permissions.
                        md5:
                          type: string
                          nullable: true
                          description: >-
                            Base64-encoded 16-byte MD5, when available; never
                            inferred from ETag.
                        expiresAt:
                          type: string
                          format: date-time
                        url:
                          type: string
                          format: uri
                          description: >-
                            Secret HTTPS provider GET capability, bound to this
                            exact immutable object version.
        '400':
          description: Invalid strict JSON body or prohibited path
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid bearer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Missing required OAuth scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >-
            Job, sample, delivered path or object unavailable; no partial
            manifest
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Job results not ready
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: Individual object or manifest exceeds 64 MiB; no URLs issued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: >-
            Immutable version, metadata or signing unavailable; details and URLs
            suppressed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      required:
        - error
        - message
      properties:
        error:
          type: string
        message:
          type: string
        reason:
          type: string
          nullable: true
        required:
          type: integer
          nullable: true
        retryAfterSeconds:
          type: integer
          nullable: true
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      bearerFormat: sk-strand-XXXXXXXXXXXXXXXXXXXXXXXX
    OAuth2:
      type: oauth2
      description: >-
        Strand AI authorization-code flow with S256 PKCE, explicit organization
        consent, and RFC 8707 resource binding.
      flows:
        authorizationCode:
          authorizationUrl: https://auth.strandai.com/oauth2/auth
          tokenUrl: https://auth.strandai.com/oauth2/token
          scopes:
            samples:read: Read slide metadata and estimates
            samples:write: Upload and change slides
            jobs:read: Read run status
            jobs:write: Start, export, or cancel runs
            results:read: Read and download results
            credits:spend: Reserve and spend organization credits

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.