> ## 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 Object Post

> This documentation provides a comprehensive overview of the POST /v1/objects endpoint of the SquareCloud Blob API.

<ParamField header="Authorization" type="string" placeholder="API Key" required>
  The API key for your account. You can find this in your [account settings](https://squarecloud.app/en/account/security).
</ParamField>

Object Post uploads a single file to Square Cloud Blob Storage and returns a CDN-backed URL you can embed or share directly, without provisioning a bucket or managing ACLs yourself. It backs attachments, generated exports, and user-uploaded media for applications hosted on the platform.

The stored extension comes from the filename you send in the multipart part (falling back to the declared MIME type, then to `bin`), so always send a real filename. Practically any file type is accepted; only executables and installers are refused. Objects can be given an automatic expiration between 7 and 1825 days (5 years), after which they're no longer served.

A single request accepts files from 512 bytes up to 100 MB, the largest body Cloudflare's edge accepts. Larger files, up to 1 GiB, go through the [chunked upload flow](/en/blob-reference/endpoint/chunked-init).

Once a file is uploaded, browse it with [Object List](/en/blob-reference/endpoint/list), remove it with [Object Delete](/en/blob-reference/endpoint/delete), or track usage against your plan's quota with [Account Stats](/en/blob-reference/endpoint/stats).

<ParamField body="file" type="file" placeholder="myphone.png" required>
  Use FormData (multipart/form-data). Exactly one file per request.<br />Send a real filename: the stored extension is derived from it.
</ParamField>

<ParamField query="name" type="string" placeholder="File Name" required>
  A string representing the name of the file. (without extension)<br />Must adhere to the a to z, A to Z, 0 to 9, and \_ pattern. (3 to 32 characters)
</ParamField>

<ParamField query="prefix" type="string" placeholder="File Prefix">
  A string representing the prefix for the file.<br />Must adhere to the a to z, A to Z, 0 to 9, and \_ pattern. (3 to 32 characters)
</ParamField>

<ParamField query="expire" type="number" placeholder="Expiration (days)">
  A number indicating the expiration period of the file, ranging from 7 to 1825 days (5 years).
</ParamField>

<ParamField query="security_hash" type="boolean" placeholder="Security Hash">
  Set to true if a security hash is required.
</ParamField>

<ParamField query="auto_download" type="boolean" placeholder="Auto Download">
  Set to true if the file should be set for automatic download.
</ParamField>

### Rate limits & concurrency

<Note>
  Uploading requires a paid plan.

  * Every account may have at most **4 uploads in progress simultaneously**. Starting another upload while 4 are still running returns `TOO_MANY_CONCURRENT_UPLOADS` (429).
  * **Hobby** and **Standard** plans are additionally limited to **1 upload per second** (`RATE_LIMITED`, 429). **Pro** and **Enterprise** plans are exempt from the per-second limit.
</Note>

<Info>
  For security, formats a browser renders inline (`.html`, `.svg`, `.xml`, `.xhtml` and similar) are always delivered as downloads (served as `application/octet-stream`) instead of being rendered. Setting `auto_download=true` applies the same forced-download behavior to any file type.
</Info>

### File types

Practically any extension is accepted, including formats with no registered MIME type (`.bam`, `.vcf`, `.fasta`, `.fastq`, `.parquet`, `.h5`, `.npy` and so on). There is no MIME allowlist anymore.

* The stored extension is derived from the **filename** sent in the multipart part, falling back to the declared MIME type, then to `bin`.
* Compound compression suffixes are preserved: `reads.fastq.gz` is stored as `.fastq.gz`, not `.gz`.
* The served `Content-Type` is derived server-side from the extension. Unknown formats are served as `application/octet-stream`, so they download instead of rendering.
* Executables and installers are refused with `BLOCKED_FILE_TYPE`: `exe`, `msi`, `dll`, `bat`, `cmd`, `com`, `scr`, `cpl`, `pif`, `hta`, `vbs`, `vbe`, `jse`, `wsf`, `wsh`, `msc`, `reg`, `lnk`, `sys`, `drv`, `ps1`, `apk`, `xpi`.

### Response

<ResponseField name="status" type="string">
  Indicates whether the call was successful. "success" if successful, "error" if not.
</ResponseField>

<ResponseField name="response" type="object">
  <Expandable title="Toggle object">
    <ResponseField name="id" type="string">
      The ID of the uploaded file.
    </ResponseField>

    <ResponseField name="name" type="string">
      The name of the uploaded file.
    </ResponseField>

    <ResponseField name="prefix" type="string">
      The prefix under which the file was stored (echoed from the `prefix` query; omitted when none was sent).
    </ResponseField>

    <ResponseField name="size" type="number">
      The size of the uploaded file, in bytes.
    </ResponseField>

    <ResponseField name="url" type="string">
      The public CDN URL of the uploaded file: `https://public-blob.squarecloud.dev/<user_id>/<key>`, where the key is `[prefix/]name[_hash][-exN].ext` (hash and expiration suffixes appear only when used; the extension is derived from the uploaded filename).
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://blob.squarecloud.app/v1/objects?name=myfile&prefix=images&expire=30' \
    --header 'Authorization: YOUR_API_KEY' \
    --form 'file=@./myphone.png'
  ```

  ```javascript JavaScript theme={null}
  import fs from 'node:fs';

  const form = new FormData();
  form.append('file', new Blob([fs.readFileSync('./myphone.png')]), 'myphone.png');

  const params = new URLSearchParams({
    name: 'myfile',
    prefix: 'images',
    expire: '30',
  });

  const response = await fetch(`https://blob.squarecloud.app/v1/objects?${params}`, {
    method: 'POST',
    headers: { Authorization: 'YOUR_API_KEY' },
    body: form,
  });
  ```

  ```python Python theme={null}
  import requests

  with open('myphone.png', 'rb') as f:
      response = requests.post(
          'https://blob.squarecloud.app/v1/objects',
          headers={'Authorization': 'YOUR_API_KEY'},
          params={'name': 'myfile', 'prefix': 'images', 'expire': 30},
          files={'file': ('myphone.png', f, 'image/png')},
      )
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
      "status": "success",
      "response": {
          "id": "3155597145698959364/images/test_lxch4k7y-07ee.png",
          "name": "test",
          "prefix": "images",
          "size": 416230,
          "url": "https://public-blob.squarecloud.dev/3155597145698959364/images/test_lxch4k7y-07ee.png"
      }
  }
  ```
</ResponseExample>

### Troubleshooting

<Tabs>
  <Tab title="400 Status Code">
    ### Object-Related

    <CodeGroup>
      ```json NAME theme={null}
      // The provided object name is invalid.
      // Must adhere to the a to z, A to Z, 0 to 9, and _ pattern.
      {
          "status": "error",
          "code": "INVALID_OBJECT_NAME"
      }
      ```

      ```json PREFIX theme={null}
      // The provided object prefix is invalid.
      // Must adhere to the a to z, A to Z, 0 to 9, and _ pattern.
      {
          "status": "error",
          "code": "INVALID_OBJECT_PREFIX"
      }
      ```

      ```json EXPIRE theme={null}
      // The provided expiration value for the object is invalid.
      // Must be a number ranging from 7 to 1825. (value in days).
      {
          "status": "error",
          "code": "INVALID_OBJECT_EXPIRE"
      }
      ```

      ```json SECURITY_HASH theme={null}
      // The provided security hash boolean is invalid.
      // Just set to true or false. 😅
      {
          "status": "error",
          "code": "INVALID_OBJECT_SECURITY_HASH"
      }
      ```

      ```json AUTO_DOWNLOAD theme={null}
      // The provided auto-download boolean is invalid.
      // Just set to true or false. 😅
      {
          "status": "error",
          "code": "INVALID_STORAGE_AUTO_DOWNLOAD"
      }
      ```
    </CodeGroup>

    ### File-Related

    <Info>A single request accepts up to 100 MB. For files up to 1 GiB, use the [chunked upload flow](/en/blob-reference/endpoint/chunked-init).</Info>

    <CodeGroup>
      ```json INVALID_FILE theme={null}
      // The provided file is invalid.
      {
          "status": "error",
          "code": "INVALID_FILE"
      }
      ```

      ```json FILETYPE theme={null}
      // The file extension is malformed or too long.
      {
          "status": "error",
          "code": "INVALID_FILE_TYPE"
      }
      ```

      ```json BLOCKED_FILE_TYPE theme={null}
      // Executable/installer extensions (exe, msi, bat, apk, ...) are not accepted.
      {
          "status": "error",
          "code": "BLOCKED_FILE_TYPE"
      }
      ```

      ```json FILE_TOO_SMALL theme={null}
      // The file size is too small (< 512 bytes).
      {
          "status": "error",
          "code": "FILE_TOO_SMALL"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="401 Status Code">
    ### Unauthorized

    <CodeGroup>
      ```json ACCESS_DENIED theme={null}
      // The API key is missing or invalid. Set a valid key in the Authorization header.
      {
          "status": "error",
          "code": "ACCESS_DENIED"
      }
      ```

      ```json PERMISSION_DENIED theme={null}
      // The account has no active paid plan. Uploading to Blob Storage requires a paid plan.
      {
          "status": "error",
          "code": "PERMISSION_DENIED"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="403 Status Code">
    ### Storage quota exceeded

    <CodeGroup>
      ```json STORAGE_QUOTA_EXCEEDED theme={null}
      // You have exceeded your storage quota. Delete some files or upgrade your plan.
      {
          "status": "error",
          "code": "STORAGE_QUOTA_EXCEEDED"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="409 Status Code">
    ### Invalid content type

    <CodeGroup>
      ```json INVALID_CONTENT_TYPE theme={null}
      // This route only accepts multipart/form-data requests with exactly one file.
      {
          "status": "error",
          "code": "INVALID_CONTENT_TYPE"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="413 Status Code">
    ### Payload too large

    <Info>A single request accepts up to 100 MB. For files up to 1 GiB, use the [chunked upload flow](/en/blob-reference/endpoint/chunked-init).</Info>

    <CodeGroup>
      ```json FILE_TOO_LARGE theme={null}
      // A single request accepts up to 100 MB. Use /v1/objects/chunked for files up to 1 GiB.
      {
          "status": "error",
          "code": "FILE_TOO_LARGE"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="429 Status Code">
    ### Rate limited

    <CodeGroup>
      ```json RATE_LIMITED theme={null}
      // Per-second upload limit reached (Hobby/Standard: max 1 upload per second).
      {
          "status": "error",
          "code": "RATE_LIMITED"
      }
      ```

      ```json TOO_MANY_CONCURRENT_UPLOADS theme={null}
      // Too many simultaneous uploads (max 4 in progress at a time per account).
      {
          "status": "error",
          "code": "TOO_MANY_CONCURRENT_UPLOADS"
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="500 Status Code">
    ### Upload failed

    <CodeGroup>
      ```json UPLOAD_FAILED theme={null}
      // Failed to upload object to storage. Please try again later.
      {
          "status": "error",
          "code": "UPLOAD_FAILED"
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>
