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

# Upload an artifact to DO Spaces and return its durable CDN URL + key.

> Upload an artifact to DO Spaces and return its durable CDN URL + key.

    Stores the object under ``<app>/YYYY/MM/<filename>`` (date derived
    server-side) in a dedicated artifact bucket, then returns a public CDN link.
    Use this whenever an agent produces a file — an image, diagram, rendered
    doc, export — that needs a real URL to attach to a ticket, post, or message.

    Provide the content exactly one of three ways:
      - ``content_base64``: raw bytes, base64-encoded.
      - ``source_url``: an http(s) URL the server fetches (size-capped, SSRF-guarded).
      - ``source_key``: the key of an object already in Spaces to copy into the
        dated path (optionally with ``source_alias`` / ``source_bucket``).

    Args:
      filename: desired filename (sanitized; extension drives content-type).
      app: optional namespace segment for the path (default "shared").
      alias: write target — "uploads" (default) or "artifacts".
      content_type: optional MIME override; otherwise guessed from the filename.

    On a name collision in the same prefix, an incrementing zero-padded suffix
    is appended before the extension (report.png → report-001.png) so existing
    objects are never clobbered. Returns JSON: {url, key, bucket, content_type, size}.



## OpenAPI

````yaml /openapi/private/specs/mcp/sagescreen.yml post /tools/upload_spaces_object
openapi: 3.1.0
info:
  title: SageScreen — MCP Tool Catalog
  description: >-
    Agent-callable tools exposed by the SageScreen MCP server at
    `https://mcp.sagescreen.net`.


    These are the same tools served over the Model Context Protocol; this
    reference documents their **REST** surface (`POST /tools/{name}`, body = the
    tool's arguments), which is what the playground below invokes. The live,
    machine-readable catalog is `GET /tools/list`.


    **This page is generated deterministically** from the server's tool registry
    (`apps/docs/scripts/generate_mcp_spec.py`), not hand-written and not
    AI-generated — it cannot drift from the shipped tools.


    All calls authenticate with the `X-Service-Token` header (or `?token=`).
  version: 1.0.0
servers:
  - url: https://mcp.sagescreen.net
    description: Production MCP server
security:
  - serviceToken: []
  - tokenQuery: []
tags:
  - name: Agents
  - name: Contact Push
  - name: Image Generation
  - name: Other
  - name: Productlane
  - name: Reply.io
  - name: Sequences
  - name: Spaces
  - name: WordPress
paths:
  /tools/upload_spaces_object:
    post:
      tags:
        - Spaces
      summary: Upload an artifact to DO Spaces and return its durable CDN URL + key.
      description: |-
        Upload an artifact to DO Spaces and return its durable CDN URL + key.

            Stores the object under ``<app>/YYYY/MM/<filename>`` (date derived
            server-side) in a dedicated artifact bucket, then returns a public CDN link.
            Use this whenever an agent produces a file — an image, diagram, rendered
            doc, export — that needs a real URL to attach to a ticket, post, or message.

            Provide the content exactly one of three ways:
              - ``content_base64``: raw bytes, base64-encoded.
              - ``source_url``: an http(s) URL the server fetches (size-capped, SSRF-guarded).
              - ``source_key``: the key of an object already in Spaces to copy into the
                dated path (optionally with ``source_alias`` / ``source_bucket``).

            Args:
              filename: desired filename (sanitized; extension drives content-type).
              app: optional namespace segment for the path (default "shared").
              alias: write target — "uploads" (default) or "artifacts".
              content_type: optional MIME override; otherwise guessed from the filename.

            On a name collision in the same prefix, an incrementing zero-padded suffix
            is appended before the extension (report.png → report-001.png) so existing
            objects are never clobbered. Returns JSON: {url, key, bucket, content_type, size}.
      operationId: upload_spaces_object
      requestBody:
        required: false
        content:
          application/json:
            schema:
              properties:
                filename:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Filename
                content_base64:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Content Base64
                source_url:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Source Url
                source_key:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Source Key
                app:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: App
                alias:
                  default: uploads
                  title: Alias
                  type: string
                content_type:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Content Type
                source_alias:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Source Alias
                source_bucket:
                  anyOf:
                    - type: string
                    - type: 'null'
                  default: null
                  title: Source Bucket
              type: object
      responses:
        '200':
          description: >-
            Tool result. The shape is tool-specific; most tools return a JSON
            object, some a `{"result": ...}` envelope.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Bad arguments (unknown kwargs, malformed JSON body).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Unknown tool name.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Tool raised an error during execution.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message.
        detail:
          type: string
          description: Optional additional context.
      required:
        - error
  responses:
    Unauthorized:
      description: Missing or invalid service token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: Unauthorized
  securitySchemes:
    serviceToken:
      type: apiKey
      in: header
      name: X-Service-Token
    tokenQuery:
      type: apiKey
      in: query
      name: token

````