---
updatedAt: 2026-05-22T07:04:47.000Z
agentTools:
  projectIndex: https://developers.dovetail.com/llms.txt
---

# Initiate a single-PUT file upload

Initiate a single-PUT upload for files **up to 5 GB**. The response includes a pre-signed `upload_url` that the client should `PUT` the full file body to. After the `PUT` succeeds, call **Complete upload** at `POST /v2/files/{file_id}/upload/complete`.

The pre-signed `upload_url` is signed for server-side encryption with AWS KMS, so the `PUT` request **must** include the header `x-amz-server-side-encryption: aws:kms`. Omitting it (or sending a different value) fails the request with a signature mismatch (HTTP `403`).

```bash
curl -X PUT "<upload_url>" \
-H "x-amz-server-side-encryption: aws:kms" \
-H "Content-Type: <type>" \
--data-binary @/path/to/file
```

Files larger than 5 GB must use the large-upload endpoint (`POST /v2/files/large-upload`) instead.

Once finalized, inspect the file with `GET /v1/files/{file_id}` and download it with `GET /v1/files/{file_id}/download` — no v2 read surface exists yet.

Returns `201` with the upload session details. Orphaned uploads that are not completed are eventually cleaned up.

# OpenAPI definition

````json
{
  "openapi": "3.0.2",
  "paths": {
    "/v2/files/upload": {
      "post": {
        "description": "Initiate a single-PUT upload for files **up to 5 GB**. The response includes a pre-signed `upload_url` that the client should `PUT` the full file body to. After the `PUT` succeeds, call **Complete upload** at `POST /v2/files/{file_id}/upload/complete`.\n\nThe pre-signed `upload_url` is signed for server-side encryption with AWS KMS, so the `PUT` request **must** include the header `x-amz-server-side-encryption: aws:kms`. Omitting it (or sending a different value) fails the request with a signature mismatch (HTTP `403`).\n\n```bash\ncurl -X PUT \"<upload_url>\" \\\n-H \"x-amz-server-side-encryption: aws:kms\" \\\n-H \"Content-Type: <type>\" \\\n--data-binary @/path/to/file\n```\n\nFiles larger than 5 GB must use the large-upload endpoint (`POST /v2/files/large-upload`) instead.\n\nOnce finalized, inspect the file with `GET /v1/files/{file_id}` and download it with `GET /v1/files/{file_id}/download` — no v2 read surface exists yet.\n\nReturns `201` with the upload session details. Orphaned uploads that are not completed are eventually cleaned up.",
        "summary": "Initiate a single-PUT file upload",
        "tags": [
          "FilesV2"
        ],
        "parameters": [],
        "requestBody": {
          "description": "Body",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 1024,
                    "description": "The file's original name, including extension. 1-1024 characters."
                  },
                  "type": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "The file's MIME type (e.g. `image/png`, `video/mp4`). Up to 255 characters."
                  },
                  "size": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5000000000,
                    "description": "Total size of the file in bytes. Must be between 1 and 5000000000 (5 GB). For files larger than 5 GB use the large-upload endpoint instead."
                  }
                },
                "required": [
                  "name",
                  "type",
                  "size"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "file_id": {
                          "type": "string",
                          "description": "Base62-encoded UUID identifying the newly created file record."
                        },
                        "upload_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Pre-signed URL the client should `PUT` the file body to."
                        },
                        "expires_at": {
                          "type": "string",
                          "description": "ISO 8601 timestamp at which `upload_url` expires."
                        },
                        "max_file_size_bytes": {
                          "type": "number",
                          "enum": [
                            5000000000
                          ],
                          "description": "Maximum size (bytes) accepted by this endpoint."
                        }
                      },
                      "required": [
                        "file_id",
                        "upload_url",
                        "expires_at",
                        "max_file_size_bytes"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "InvalidOperation"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          },
                          "path": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "Unauthorized"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "403",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "Forbidden"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "404",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "NotFound"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "422",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "UnprocessableContent"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title",
                          "message"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "429",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "TooManyRequests"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "500",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "InternalError"
                            ]
                          },
                          "title": {
                            "type": "string",
                            "enum": [
                              "Internal server error"
                            ]
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "title"
                        ]
                      }
                    }
                  },
                  "required": [
                    "errors"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "info": {
    "title": "Dovetail Public API",
    "version": "0.0.1",
    "description": "The Dovetail Public API provides programmatic access to your Dovetail workspace.\n\n## Core concepts\n\n- **Projects** — Containers for organizing qualitative research. They hold data, docs, highlights, tags, and insights.\n- **Data** — Documents within a project that capture raw research data such as interview transcripts, survey responses, and session recordings. Available via `/v1/data`. The legacy `/v1/notes` endpoints access the same underlying resource.\n- **Docs** — Rich-text documents for writing up research reports, sharing findings, and publishing deliverables. Docs replace the deprecated insights resource.\n- **Highlights** — Selected passages of text or time ranges in transcripts that have been marked as significant during analysis.\n- **Tags** — Labels applied to highlights to categorize findings (e.g. 'Usability Issue', 'Feature Request').\n- **Channels** — Automated AI-powered pipelines that continuously analyze high-volume customer feedback (app reviews, NPS, support tickets) into structured topics.\n- **Contacts** — People in your contacts database such as interview participants or customers.\n- **Folders** — Hierarchical containers for organizing projects, docs, channels, and other content.\n- **Files** — Attachments (images, documents, audio, video) that can be embedded in docs, data entries, or insights.\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header. Generate API tokens from your Dovetail workspace settings.\n\n## Base URL\n\nAll API endpoints are served under `https://dovetail.com/api`."
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    }
  },
  "servers": [
    {
      "url": "https://dovetail.com/api"
    },
    {
      "url": "https://dovetailapp.com/api"
    }
  ]
}
````