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

# Reserve a direct upload from the widget

> Reserves storage for a file and returns a one-time URL to `PUT` the bytes to. Two steps, not one:

1. `POST` here with the file's name, size, MIME type and base64 MD5 checksum.
2. `PUT` the bytes to `direct_upload.url` with the headers it gives you. The upload is rejected if the bytes disagree with the size or checksum you declared.

Then send `signed_id` as the attachment when you create the message. This is the widget's only upload path — the account-level `POST /upload` needs an `api_access_token`, which a widget session does not have.



## OpenAPI

````yaml /api-reference/openapi.json post /api/v1/widget/direct_uploads
openapi: 3.0.4
info:
  title: Tied API
  description: >-
    The Tied REST API. Three families of endpoint, each with its own credential:
    **Application** for everything inside an account, **Platform** for
    provisioning accounts and users, and **Client** for acting as a contact from
    your own surface.
  version: 1.1.0
  termsOfService: https://tied.com/legal
  contact:
    email: hello@tied.com
  license:
    name: MIT License
    url: https://opensource.org/licenses/MIT
servers:
  - url: https://app.tied.com
    description: Tied cloud
security: []
tags:
  - name: Account AgentBots
    description: Account-specific Agent Bots
  - name: Agents
    description: Agent management APIs
  - name: Canned Responses
    description: Pre-defined responses for common queries
  - name: Contacts
    description: Contact management APIs
  - name: Contact Labels
    description: Manage contact labels
  - name: Conversation Assignments
    description: Manage conversation assignments
  - name: Conversation Labels
    description: Manage conversation labels
  - name: Conversations
    description: Conversation management APIs
  - name: Custom Attributes
    description: Custom fields for contacts and conversations
  - name: Custom Filters
    description: Saved filters for conversations
  - name: Inboxes
    description: Communication channels setup
  - name: Integrations
    description: Third-party integrations
  - name: Messages
    description: Message management APIs
  - name: Profile
    description: User profile APIs
  - name: Reports
    description: Analytics and reporting APIs
  - name: Teams
    description: Team management APIs
  - name: Webhooks
    description: Event notification webhooks
  - name: Automation Rule
    description: Workflow automation rules
  - name: Help Center
    description: Knowledge base management
  - name: Contacts API
    description: Public contact APIs
  - name: Conversations API
    description: Public conversation APIs
  - name: Messages API
    description: Public message APIs
  - name: CSAT Survey Page
    description: Customer satisfaction survey
  - name: Account
    description: >-
      The authenticated user's own account — read and update account settings.
      Distinct from the Platform family's **Accounts**, which provisions
      accounts across an installation.
  - name: Audit Logs
    description: Read the account's audit trail
  - name: Inbox API
    description: Public inbox lookup by channel identifier
  - name: Labels
    description: >-
      Create and manage the account's labels. Applying one to a conversation or
      contact is a separate endpoint under those resources.
  - name: Macros
    description: >-
      Saved multi-step actions an agent — or an integration — can run against
      one or more conversations.
  - name: Campaigns
    description: Ongoing website campaigns and one-off SMS and WhatsApp sends.
  - name: Contact Notes
    description: Internal notes on a contact. Never visible to the contact.
  - name: Help Center Categories
    description: Categories group a portal's articles, one tree per allowed locale.
  - name: Help Center Articles
    description: The articles a portal publishes, and their draft and archived states.
  - name: Summary Reports
    description: Per-agent, per-team, per-inbox and per-label totals for a period, as JSON.
  - name: Live Reports
    description: Right-now queue counts. No date range — these describe the present.
  - name: CSAT
    description: >-
      The satisfaction ratings contacts have submitted, and the metrics computed
      from them.
  - name: Notifications
    description: >-
      The per-user notification feed, its read and snooze state, and the
      settings that decide what lands in it.
  - name: Conversation Participants
    description: >-
      The agents watching a conversation. Participants get notified about it
      without being assigned to it.
  - name: Draft Messages
    description: >-
      The unsent reply held for a conversation. Stored in Redis, one per
      conversation.
  - name: Search
    description: >-
      One search service across conversations, contacts, messages and Help
      Center articles.
  - name: Dashboard Apps
    description: Embedded pages that appear as a tab beside a conversation.
  - name: Assignment Policies
    description: How conversations are handed out, and which inbox uses which policy.
  - name: Files
    description: Storing a file so another endpoint can attach it.
  - name: Bot Flows
    description: >-
      Scripted conversation flows, their versions, and the publish and rollback
      that move between them.
  - name: Billing
    description: >-
      Credit balance, usage, invoices, spend controls and the provider-hosted
      payment flows.
  - name: AMB Templates
    description: >-
      Saved Apple Messages primitive payloads an agent can reuse from the
      composer.
  - name: AMB Onboarding
    description: The in-flight Apple Messages for Business registration for an account.
  - name: Widget Session
    description: Starting a widget session and reading the visitor it belongs to.
  - name: Widget Conversation
    description: The visitor's conversation and its messages.
  - name: Widget Context
    description: Campaigns, agents, labels, events and uploads for a widget session.
  - name: CSAT Survey
    description: The public, unauthenticated survey a contact answers from a link.
  - name: Workspace
    description: Scheduling and cancelling deletion of the whole workspace.
paths:
  /api/v1/widget/direct_uploads:
    post:
      tags:
        - Widget Context
      summary: Reserve a direct upload from the widget
      description: >-
        Reserves storage for a file and returns a one-time URL to `PUT` the
        bytes to. Two steps, not one:


        1. `POST` here with the file's name, size, MIME type and base64 MD5
        checksum.

        2. `PUT` the bytes to `direct_upload.url` with the headers it gives you.
        The upload is rejected if the bytes disagree with the size or checksum
        you declared.


        Then send `signed_id` as the attachment when you create the message.
        This is the widget's only upload path — the account-level `POST /upload`
        needs an `api_access_token`, which a widget session does not have.
      operationId: create-widget-direct-upload
      parameters:
        - $ref: '#/components/parameters/website_token'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/direct_upload_payload'
            example:
              blob:
                filename: receipt.png
                byte_size: 27
                checksum: janaQDJaHWRN47FY/qJ9kQ==
                content_type: image/png
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/direct_upload_blob'
              example:
                id: 22
                key: 8n6pgvrx80plu9nx49f6czgh7jq1
                filename: receipt.png
                content_type: image/png
                metadata: {}
                byte_size: 27
                checksum: janaQDJaHWRN47FY/qJ9kQ==
                created_at: '2026-09-21T05:13:10.955Z'
                service_name: local
                attachable_sgid: >-
                  eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaEpJalZuYVdRNkx5OWphR0YwZDI5dmRDOUJZM1JwZG1WVGRHOXlZV2RsT2pwQ2JHOWlMekl5UDJWNGNHbHlaWE5mYVc0R09nWkZWQT09IiwiZXhwIjpudWxsLCJwdXIiOiJhdHRhY2hhYmxlIn19--EXAMPLE
                signed_id: >-
                  eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBHdz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--EXAMPLE
                direct_upload:
                  url: >-
                    https://app.tied.com/rails/active_storage/blobs/proxy/EXAMPLE/asset.png
                  headers:
                    Content-Type: image/png
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error_message'
      security:
        - widgetAuthToken: []
components:
  parameters:
    website_token:
      name: website_token
      in: query
      required: true
      description: >-
        The web-widget inbox's public token, as it appears in your widget
        snippet. Required on every widget request.
      schema:
        type: string
        example: EXAMPLE_WEBSITE_TOKEN
  schemas:
    direct_upload_payload:
      type: object
      required:
        - blob
      properties:
        blob:
          type: object
          required:
            - filename
            - byte_size
            - checksum
            - content_type
          description: >-
            Describe the file before sending it. All four fields are required,
            and the subsequent PUT is rejected if the bytes disagree with
            `byte_size` or `checksum`.
          properties:
            filename:
              type: string
              description: The file name.
              example: orders.csv
            byte_size:
              type: integer
              description: Size in bytes.
              example: 27
            checksum:
              type: string
              description: Base64-encoded MD5 of the file contents.
              example: janaQDJaHWRN47FY/qJ9kQ==
            content_type:
              type: string
              description: MIME type.
              example: text/csv
    direct_upload_blob:
      type: object
      description: >-
        The stored blob plus the one-time URL to PUT the bytes to. This is
        Rails' ActiveStorage direct-upload response, passed through unchanged.
      properties:
        id:
          type: integer
          description: The blob's numeric ID.
        key:
          type: string
          description: The storage key.
        filename:
          type: string
          description: The filename you declared.
        content_type:
          type: string
          description: The content type you declared.
        byte_size:
          type: integer
          description: >-
            The size you declared. The upload is rejected if the bytes do not
            match it.
        checksum:
          type: string
          description: >-
            The base64 MD5 you declared. The upload is rejected if the bytes do
            not match it.
        metadata:
          type: object
          description: Metadata ActiveStorage derives once the bytes arrive.
        service_name:
          type: string
          description: Which storage service holds it.
        created_at:
          type: string
          description: ISO-8601 timestamp.
        signed_id:
          type: string
          description: What you send as the attachment reference when creating the message.
        attachable_sgid:
          type: string
          description: Signed global ID for the blob, used by rich-text attachment flows.
        direct_upload:
          type: object
          description: Where and how to send the bytes.
          properties:
            url:
              type: string
              description: >-
                One-time URL to `PUT` the file to. Short-lived — upload
                immediately rather than storing it.
            headers:
              type: object
              description: >-
                Headers the `PUT` must carry, including the content type and
                checksum.
    error_message:
      type: object
      description: >-
        The shape returned by `render_unauthorized`, `render_not_found_error`
        and `render_could_not_create_error`.
      properties:
        error:
          type: string
          description: A single human-readable message.
          example: Resource could not be found
      required:
        - error
  securitySchemes:
    widgetAuthToken:
      type: apiKey
      in: header
      name: X-Auth-Token
      description: >-
        The signed session token from `POST /api/v1/widget/config`. Sent
        alongside `website_token` in the query string on every widget request.
        See /api-reference/widget-api-authentication.

````

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