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

# Blob Upload Tokens

> Erstelle mit POST /v1/upload-tokens ein kurzlebiges Upload-Token, damit ein Browser ohne deinen API-Schlüssel direkt in Blob Storage hochladen kann.

<ParamField header="Authorization" type="string" placeholder="API Key" required>
  Der API-Schlüssel für Ihr Konto. Sie finden ihn in Ihren [Kontoeinstellungen](https://squarecloud.app/de/account/security).
</ParamField>

Mit Upload Tokens erstellt dein **Server** ein kurzlebiges Token, das ein **Browser** oder eine mobile App verwendet, um direkt in Blob Storage hochzuladen. Die Datei läuft nie über deinen Server, und dein API-Schlüssel verlässt ihn nie. Erfordert den Scope `blob:write` und einen kostenpflichtigen Plan.

Das Token kommt in den Header `Authorization` von [Object Post](/de/blob-reference/endpoint/post) oder den Routen des [Chunked Uploads](/de/blob-reference/endpoint/chunked-init) und funktioniert nirgendwo sonst (`403 UPLOAD_TOKEN_NOT_ALLOWED`). Alles, was du beim Erstellen festlegst, ist **fixiert**: Der Browser kann Name, Präfix, Sichtbarkeit, Ablauf oder Metadaten nicht ändern, keine größere Datei senden und keinen anderen Dateityp verwenden.

* Jeder Upload verbraucht eine Nutzung: ein Aufruf von Object Post oder das Öffnen eines Chunked Uploads (dessen Teile und Abschluss verbrauchen keine weiteren).
* Ohne `name` wählt der Browser ihn, und der Name erhält immer einen Security Hash, sodass ein geleaktes Token niemals deine bestehenden Dateien ersetzen kann.
* Das Token funktioniert nicht mehr, wenn seine Nutzungen aufgebraucht sind (`401 UPLOAD_TOKEN_USED`), wenn es abläuft oder wenn der API-Schlüssel, der es erstellt hat, widerrufen wird (`401 ACCESS_DENIED`).

<ParamField body="name" type="string">
  Fixiert den Dateinamen. Ohne ihn sendet der Browser `name` in der Query.
</ParamField>

<ParamField body="prefix" type="string">
  Fixiert das Präfix. Ein Browser, der ein anderes sendet, erhält `403 PREFIX_NOT_ALLOWED`.
</ParamField>

<ParamField body="private" type="boolean">
  Fixiert die Sichtbarkeit.
</ParamField>

<ParamField body="security_hash" type="boolean">
  Nur mit `name`: `false` erlaubt dem Upload, die Datei mit diesem Namen zu ersetzen. Andernfalls erhält der Name immer einen Hash.
</ParamField>

<ParamField body="expire" type="string | null">
  Fixiert den Ablauf (`30d`, `6h`) oder `null` für keinen. Unter 7 Tagen erfordert Enterprise.
</ParamField>

<ParamField body="max_size" type="number">
  Maximale Dateigröße in Bytes, von 512 bis 10737418240 (10 GiB).
</ParamField>

<ParamField body="allowed_extensions" type="string[]">
  Akzeptierte Endungen, 1 bis 20, in Kleinbuchstaben und ohne Punkt (`png`, `tar.gz`).
</ParamField>

<ParamField body="metadata" type="object">
  Metadaten, die jeder mit dem Token hochgeladenen Datei hinzugefügt werden. Nur Pro und Enterprise.
</ParamField>

<ParamField body="expires_in" type="number" default="900">
  Wie lange das Token gilt, von 60 bis 3600 Sekunden.
</ParamField>

<ParamField body="max_uses" type="number" default="1">
  Wie viele Uploads das Token erlaubt, von 1 bis 100.
</ParamField>

### Rate Limits

<Note>120 Tokens pro Minute (`RATE_LIMITED`, 429). Das Erstellen speichert nichts, daher ist ein Token pro Upload eines Endnutzers in Ordnung.</Note>

### Antwort

<ResponseField name="status" type="string">
  "success" bei Erfolg, "error" bei Misserfolg.
</ResponseField>

<ResponseField name="response" type="object">
  <Expandable title="Objekt umschalten">
    <ResponseField name="token" type="string">
      Das Upload-Token (`squp_...`). Gib es an den Browser weiter.
    </ResponseField>

    <ResponseField name="expires_at" type="ISO 8601">
      Wann das Token abläuft.
    </ResponseField>

    <ResponseField name="max_uses" type="number">
      Wie viele Uploads das Token erlaubt.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```javascript Server (Node.js) theme={null}
  // Your backend: mint a token for the signed-in user and return it to the page.
  const res = await fetch('https://blob.squarecloud.app/v1/upload-tokens', {
    method: 'POST',
    headers: {
      Authorization: process.env.SQUARE_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      prefix: `avatars/${userId}`,
      allowed_extensions: ['png', 'jpg', 'webp'],
      max_size: 2 * 1024 * 1024,
      expires_in: 300,
    }),
  });
  const { response } = await res.json();
  // send response.token to the browser
  ```

  ```javascript Browser theme={null}
  const form = new FormData();
  form.append('file', input.files[0]);

  const res = await fetch('https://blob.squarecloud.app/v1/objects?name=avatar', {
    method: 'POST',
    headers: { Authorization: token },
    body: form,
  });
  const { response } = await res.json();
  // response.url is the public URL of the new file
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://blob.squarecloud.app/v1/upload-tokens' \
    --header 'Authorization: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{ "prefix": "avatars", "allowed_extensions": ["png", "jpg"], "max_size": 2097152 }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "status": "success",
    "response": {
      "token": "squp_Tq7xLm2Vb9Rk4Wz1Nc8Hy5Js0Gd3Fp6Ae.Hq3mZ8vT1kLw9xRb",
      "expires_at": "2026-09-25T12:15:00.000Z",
      "max_uses": 1
    }
  }
  ```
</ResponseExample>

### Fehler

| Code                                                                                                                                                              | HTTP | Wann                                                                              |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------- |
| `INVALID_BODY`                                                                                                                                                    | 400  | Der Body ist kein JSON-Objekt.                                                    |
| `INVALID_OBJECT_NAME` / `INVALID_OBJECT_PREFIX` / `INVALID_OBJECT_PRIVATE` / `INVALID_OBJECT_SECURITY_HASH` / `INVALID_OBJECT_EXPIRE` / `INVALID_OBJECT_METADATA` | 400  | Ein fixierter Wert ist ungültig.                                                  |
| `INVALID_MAX_SIZE` / `INVALID_ALLOWED_EXTENSIONS` / `INVALID_EXPIRES_IN` / `INVALID_MAX_USES`                                                                     | 400  | Ein Limit liegt außerhalb des Bereichs.                                           |
| `UPLOAD_TOKEN_TOO_LARGE`                                                                                                                                          | 400  | Zu viele Optionen für ein Token. Kürze die Metadaten oder die Liste der Endungen. |
| `PERMISSION_DENIED`                                                                                                                                               | 401  | Das Konto hat keinen aktiven kostenpflichtigen Plan.                              |
| `UPGRADE_REQUIRED`                                                                                                                                                | 403  | Der Ablauf oder die Metadaten erfordern einen höheren Plan.                       |
| `RATE_LIMITED`                                                                                                                                                    | 429  | Mehr als 120 Tokens in einer Minute.                                              |

Wenn der Browser hochlädt: `401 UPLOAD_TOKEN_USED` (aufgebraucht), `401 ACCESS_DENIED` (abgelaufen oder widerrufen), `403 PREFIX_NOT_ALLOWED` (anderes Präfix), `400 FILE_TYPE_NOT_ALLOWED` (Endung nicht erlaubt) und `413 FILE_TOO_LARGE` (über `max_size`).
