Pular para o conteúdo principal
POST
/
v2
/
files
/
sign
Upload Large File - Step 1: Sign
curl --request POST \
  --url https://api.tess.im/v2/files/sign \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "filename": "<string>",
  "content_type": "<string>",
  "size": 123
}
'
import requests

url = "https://api.tess.im/v2/files/sign"

payload = {
"filename": "<string>",
"content_type": "<string>",
"size": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({filename: '<string>', content_type: '<string>', size: 123})
};

fetch('https://api.tess.im/v2/files/sign', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tess.im/v2/files/sign",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'filename' => '<string>',
'content_type' => '<string>',
'size' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://api.tess.im/v2/files/sign"

payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"content_type\": \"<string>\",\n \"size\": 123\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.tess.im/v2/files/sign")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"content_type\": \"<string>\",\n \"size\": 123\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.tess.im/v2/files/sign")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"<string>\",\n \"content_type\": \"<string>\",\n \"size\": 123\n}"

response = http.request(request)
puts response.read_body
{
  "uploadUrl": "<string>",
  "objectPath": "<string>",
  "requiredHeaders": {},
  "finalUrl": "<string>"
}
Use este endpoint sempre que o arquivo for maior que 32 MB. Para arquivos de até 32 MB, o endpoint single-shot POST /files é mais simples e continua suportado.

Como funciona

O corpo do arquivo é enviado diretamente do cliente para o Google Cloud Storage usando uma URL PUT assinada V4 de curta duração — os bytes nunca passam pelo servidor da API, o que permite que o endpoint aceite arquivos de até 200 MB. Um único upload são três chamadas do cliente:
  1. POST /v2/files/sign — a API gera uma URL PUT assinada para o GCS válida por ~15 minutos e retorna os headers que o cliente deve repetir no PUT.
  2. PUT do corpo do arquivo diretamente para a uploadUrl retornada. O PUT carrega exatamente os headers de requiredHeaders — nem mais, nem menos — eles estão vinculados à assinatura V4, então um header faltando, extra ou diferente faz o GCS rejeitar o PUT com 403.
  3. POST /v2/files/register — a API verifica o tamanho do objeto enviado contra o que você declarou no /sign, move-o server-side da área de staging temporária para o local final, faz deduplicação por hash de conteúdo, e retorna o FileDTO padrão (mesmo formato de POST /files).

Etapa 2 — PUT direto para o Google Cloud Storage

Envie exatamente os headers retornados em requiredHeaders (atualmente Content-Type e x-goog-if-generation-match):
cURL
curl --request PUT \
  --url 'COLE_uploadUrl_AQUI' \
  --header 'Content-Type: application/pdf' \
  --header 'x-goog-if-generation-match: 0' \
  --upload-file './report.pdf'
O GCS retorna 200 em caso de sucesso. O header x-goog-if-generation-match: 0 torna o PUT create-only — re-execuções retornam 412 Precondition Failed.

Etapa 3 — registrar o upload

Após o PUT ser bem-sucedido, finalize o upload. O tamanho declarado não precisa ser enviado de novo — o servidor lembra o size que você declarou no /sign (por ~16 minutos) e o compara com o objeto realmente enviado:
cURL
curl --request POST \
  --url 'https://api.tess.im/v2/files/register' \
  --header 'Authorization: Bearer <TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
    "object_path": "<objectPath retornado por /sign>",
    "filename": "report.pdf",
    "content_type": "application/pdf",
    "process": false
  }'
Retorna 201 com o FileDTO padrão. Se um arquivo com conteúdo idêntico já existir no workspace, a API retorna 200 com o FileDTO do arquivo existente em vez de criar uma duplicata. O campo opcional process funciona exatamente como em POST /files.

Arquivos suportados

Os mesmos de POST /files — Texto, Word, Planilha, PDF, Excel, PowerPoint, Imagem, Vídeo, Áudio e mais de 30 extensões de código.

Limites

  • Tamanho máximo por upload: 200 MB
  • Um arquivo por fluxo (execute as três etapas novamente para arquivos adicionais)
  • Limite de armazenamento: 30 arquivos

Erros

StatusSignificado
400Validação do /register falhou (campo ausente ou object_path mal formado)
401Token Bearer ausente ou inválido
403Caller não tem permissão de API para o workspace alvo — ou, no PUT do GCS, os headers não correspondem a requiredHeaders
404Sessão de upload expirada (janela de ~15 minutos) ou desconhecida, ou o objeto nunca foi enviado — recomece pelo /sign
412No PUT do GCS: o objeto já existe (a URL assinada é create-only)
415content_type não suportado no /register
422Validação do /sign falhou (campo ausente ou size > 200 MB) — ou o objeto enviado é maior que o tamanho declarado no /sign (o objeto é excluído)
429Throttled

Autorizações

Authorization
string
header
obrigatório

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Cabeçalhos

x-workspace-id
integer

ID of the workspace. If not provided, the user's selected workspace will be used.

Corpo

application/json
filename
string
obrigatório

Original filename including extension (e.g. report.pdf). Used to derive the stored extension.

content_type
string
obrigatório

MIME type of the file. Bound into the signed URL - the client MUST PUT with exactly this Content-Type header.

size
integer
obrigatório

Declared file size in bytes. The server remembers this value and /register rejects the upload if the actual uploaded object is larger than declared. Hard maximum: 200 MB (209715200 bytes).

Resposta

Signed PUT URL minted.

uploadUrl
string<uri>

Pre-signed Google Cloud Storage PUT URL. Valid for ~15 minutes.

objectPath
string

GCS object path the file will land at. Pass this back to POST /v2/files/register.

requiredHeaders
object

Headers the client MUST send on the PUT - bound into the V4 signature. Contains exactly Content-Type (the value you declared) and x-goog-if-generation-match: 0 (create-only). Send these headers verbatim and do not add others.

finalUrl
string<uri>

Short-lived signed download URL (~3 hours) for the uploaded object. For a durable reference, use the url field of the FileDTO returned by POST /v2/files/register.