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

# Start an upload

> Starts a direct upload: you declare the file's name, size and SHA-256, and ROOTKey answers with a signed URL (or a part plan, for a large file) to send the bytes to. Nothing is anchored and nothing is consumed from your plan until you [complete the upload](/api-reference/platform/endpoint/files/complete-file-upload). Read [Direct file uploads](/api-reference/platform/endpoint/files/direct-uploads) first for the whole flow.



## OpenAPI

````yaml post /platform/files/uploads
openapi: 3.0.3
info:
  title: ROOTKey Documentation
  description: >-
    Your API of choice for creating, managing, and validating information easily
    and securely!
  termsOfService: https://www.rootkey.ai/legal/privacy-policy
  contact:
    name: ROOTKey
    url: https://www.rootkey.ai/contact
    email: support@rootkey.ai
  version: 1.0.0
servers:
  - description: Production
    url: https://api.rootkey.ai/api-v1/
security:
  - x-api-key: []
tags:
  - name: api-v1-public
    description: Unauthenticated top-level /api-v1 endpoints (health, plans, annual report)
  - name: api-v1-files
    description: >-
      File anchoring, versioning, validation and compliance reporting
      (/api-v1/platform/files)
  - name: api-v1-records
    description: Structured-data record anchoring (/api-v1/platform/records)
  - name: api-v1-vaults
    description: 'Vault lifecycle: create / update / delete (/api-v1/platform/vaults)'
  - name: api-v1-recovery-points
    description: >-
      Backup archives created from vault contents
      (/api-v1/platform/recovery-point)
paths:
  /platform/files/uploads:
    post:
      tags:
        - api-v1-files
      summary: Start an upload
      description: >-
        Starts a direct upload: you declare the file's name, size and SHA-256,
        and ROOTKey answers with a signed URL (or a part plan, for a large file)
        to send the bytes to. Nothing is anchored and nothing is consumed from
        your plan until you [complete the
        upload](/api-reference/platform/endpoint/files/complete-file-upload).
        Read [Direct file
        uploads](/api-reference/platform/endpoint/files/direct-uploads) first
        for the whole flow.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ownerVault
                - fileName
                - size
                - sha256
                - contentType
              properties:
                ownerVault:
                  type: string
                  description: >-
                    Address of the vault that will own the file. `ownerWallet`
                    is accepted as an alias.
                  example: '0xdf67CA8286510997567685c0385ECeAb11C23C92'
                fileName:
                  type: string
                  maxLength: 255
                  description: >-
                    The file's name, with its extension. This is the name the
                    file shows in the vault.
                  example: contract.pdf
                size:
                  type: integer
                  minimum: 0
                  description: >-
                    The file's size in bytes. The bytes you upload must be
                    exactly this long.
                  example: 2621440
                sha256:
                  type: string
                  pattern: ^[0-9a-fA-F]{64}$
                  description: >-
                    The SHA-256 of the whole file, as 64 hexadecimal characters.
                    This is the hash that gets anchored.
                  example: >-
                    9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
                contentType:
                  type: string
                  description: >-
                    The file's media type. ROOTKey keeps it for types that
                    browsers do not execute (PDF, images, plain text, CSV, JSON,
                    archives, office documents, audio and video) and stores
                    anything else as `application/octet-stream`. The
                    `Content-Type` in the response says which.
                  example: application/pdf
                parentId:
                  type: string
                  description: >-
                    Upload a new version of this file instead of a new file. The
                    file must be in the same vault.
                expirationDate:
                  type: string
                  format: date-time
                  description: Optional expiry date-time for the smart contract
      responses:
        '201':
          description: >-
            Upload started. `mode` says how to send the bytes: `single` carries
            one signed URL, `multipart` carries a part plan.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SinglePutUpload'
                  - $ref: '#/components/schemas/MultipartUpload'
        '400':
          description: >-
            The request failed a check: a malformed body, an invalid vault
            address, a paused vault, or a plan limit (`usage_limit_exceeded`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainErrorResponse'
        '401':
          description: Unauthenticated
        '404':
          description: >-
            The vault or the parent file does not exist in your organization
            (`resource_not_found`), or direct uploads are not available on this
            deployment (`presigned_file_upload_disabled`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainErrorResponse'
        '413':
          description: '`file_too_large`: the file is larger than the 5 GiB maximum.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainErrorResponse'
        '429':
          description: >-
            Your organization has too much open at once, and nothing was
            created: `too_many_open_file_uploads` or
            `too_many_open_file_upload_bytes`. Complete or abort some uploads
            ([list
            them](/api-reference/platform/endpoint/files/list-file-uploads)), or
            wait for them to expire, then try again. A `429` with
            `rate_limit_exceeded` is the rate limit instead: see the
            `Retry-After` header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainErrorResponse'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - x-api-key: []
components:
  schemas:
    SinglePutUpload:
      type: object
      properties:
        uploadId:
          type: string
          example: upl_3f2b8c1e5a7d4e9b9c2a1d6e8f0a4b7c
        fileId:
          type: string
          description: The id the file will have once the upload is completed.
        mode:
          type: string
          enum:
            - single
        expiresAt:
          type: string
          format: date-time
          description: You can complete the upload until this time.
        upload:
          $ref: '#/components/schemas/PresignedRequest'
    MultipartUpload:
      type: object
      properties:
        uploadId:
          type: string
          example: upl_3f2b8c1e5a7d4e9b9c2a1d6e8f0a4b7c
        fileId:
          type: string
          description: The id the file will have once the upload is completed.
        mode:
          type: string
          enum:
            - multipart
        expiresAt:
          type: string
          format: date-time
          description: You can complete the upload until this time.
        partSize:
          type: integer
          description: Bytes in each part. The last part is the remainder.
        partCount:
          type: integer
          description: How many parts the file is split into.
    DomainErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            requestId:
              type: string
            message:
              type: string
            errorCode:
              type: string
            docUrl:
              type: string
            timestamp:
              type: string
              format: date-time
    PresignedRequest:
      type: object
      properties:
        method:
          type: string
          enum:
            - PUT
        url:
          type: string
          format: uri
          description: Send the bytes to this URL.
        headers:
          type: object
          additionalProperties:
            type: string
          description: >-
            Send exactly these headers. They are part of the signature, so a
            different value is refused by the storage. The object can be empty.
            Your HTTP client sets `Content-Length` itself.
        expiresAt:
          type: string
          format: date-time
          description: The request must start before this time.
  responses:
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/DomainErrorResponse'
  securitySchemes:
    x-api-key:
      type: apiKey
      name: x-api-key
      in: header
      description: >-
        ROOTKey API key (rk_live_... for production, rk_test_... for the test
        network).

````

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