# Object Storage Blob store backed by Cloudflare R2. Upload via the edge proxy (authenticated), read directly via permanent public URL (no key). ## Prerequisites Edge calls require this resource to be provisioned first; unprovisioned calls return an error. ### Provision curl -s -X POST https://cohesivity.ai/api/resources/object-storage \ -H "Authorization: Bearer " ### Delete curl -s -X DELETE https://cohesivity.ai/api/resources/object-storage \ -H "Authorization: Bearer " Provisioning happens once, before the application runs; the running application does not provision its own resources. ## Common Mistakes - **Using the original filename for download/delete.** Upload adds a random hash to the filename for security (e.g., `cat.jpg` → `cat-a3f8b2c1d4e5f6g7.jpg`), so the `path` from the upload response, not the original filename, is the value to persist and reuse. - **Putting `?key=` URLs in browser-visible HTML.** An `` tag exposes the application key to anyone who views the page source. The `url` from the upload response is the safe alternative: a permanent public link with no key. - **Trying to GET via the edge proxy.** Reads go directly through the `url` returned by upload; the edge proxy only handles PUT (upload) and DELETE. > **Server-side only.** `coh_application_key` is a secret; browser JS, mobile bundles, and other client-side code cannot hold it safely. This call belongs in a Railway-hosted server, `cloudflare-workers`, or your own server tier. See the canonical key-secrecy directive in `.cohesivity` for details. **CORS:** edge endpoints set `Access-Control-Allow-Origin: *` so a server-side proxy can be hit from any origin (the proxy itself stays on your server tier; only the response is browser-visible). **Upload response:** `{ ok, path, url, requested_path, path_was_mutated }`. `requested_path` echoes the raw input you sent; `path` is the stored hashed key (which is what you must persist for DELETE / DB indexing). `path_was_mutated` is always `true` for PUT today because every upload gets a random hash suffix: the field is wire-stable for callers that want a single check rather than comparing strings. ## How It Works Object storage is a blob store: write by path, read by path. 1. **Upload** goes through the edge proxy (authenticated): `PUT /edge/object-storage/?key=` 2. The response returns `{ok, path, url}`: `path` has a random hash suffix, `url` is a permanent public link 3. **`path`** persists in the database alongside the related data, forming the file index 4. **Reads** use the `url` directly (e.g., ``), served from Cloudflare's CDN with no key and no proxy 5. **Delete** goes through the edge proxy (authenticated): `DELETE /edge/object-storage/?key=` ## Upload PUT https://cohesivity.ai/edge/object-storage/?key= Content-Type: image/jpeg Body: Response: { "ok": true, "path": "photos/cat-a3f8b2c1d4e5f6g7.jpg", "url": "https://storage.cohesivity.ai//photos/cat-a3f8b2c1d4e5f6g7.jpg", "requested_path": "photos/cat.jpg", "path_was_mutated": true } - `path`: the stored filename (with random hash). Use this for DELETE and store it in your database. - `url`: permanent public URL. Use this in ``, ``, etc. Served from Cloudflare's CDN. - `requested_path`: the raw path you sent, echoed back for confirmation/logging. - `path_was_mutated`: `true` whenever the stored `path` differs from `requested_path` (always today, since every upload gets a hash suffix). Lets agents detect mutation in one boolean check rather than diffing strings. - Content-Type is preserved: whatever you set on upload is served on read. ## Delete DELETE https://cohesivity.ai/edge/object-storage/?key= Use the `path` from the upload response (the hashed filename). ## Behavior - **Filenames get a random hash suffix.** `photos/cat.jpg` becomes `photos/cat-a3f8b2c1d4e5f6g7.jpg`. This makes URLs unguessable: knowing the original filename is not enough to access the file. - **Reads go direct to CDN.** The `url` from upload points to Cloudflare's CDN. No Cohesivity proxy, no key in the URL. - **Blob store model.** Upload returns the file path: store it in your database alongside your data. This is your file index, just like any CDN or blob store. - **Path rules:** no `..` (directory traversal blocked); leading/trailing slashes are trimmed; backslashes are normalized to `/`. Paths are case-sensitive. - **Upload size:** governed by the Rate Limits section below and the account bucket/fluid model. - **Egress:** Free: no bandwidth charges for reads. - **For images:** client-side compression and resizing before upload keeps files small; a max of 1200px on the longest side at JPEG quality 0.8 is a reasonable default. ## Rate Limits Ephemeral tenants pause as a whole if any authoritative hard cap below is exceeded. Claimed tiers use account-scoped buckets shared across every project owned by the Cohesivity user; OpenAI, AI Gateway, Deepgram, and Exa are fluid-only after tier, rate, and concurrency checks; AI Gateway and Deepgram have no fixed monthly usage bucket for claimed tiers. **Ephemeral** - uploads: 250 per ephemeral tenant lifetime before claim or expiry - uploaded bytes: 2 GB per ephemeral tenant lifetime before claim or expiry - live storage: 1 GB max total - uploads: 10 per minute **Claimed Free** - live storage: 10 GB max total - uploads: 30 per minute - uploads: 10000 per month - uploaded bytes: 50 GB per month **Claimed Plus** - live storage: 100 GB max total - uploads: 150 per minute - uploads: 100000 per month - uploaded bytes: 500 GB per month **Claimed Pro** - live storage: 500 GB max total - uploads: 750 per minute - uploads: 500000 per month - uploaded bytes: 2500 GB per month ### Notes - Public reads on `storage.cohesivity.ai` bypass the main Worker today. Upload/delete/storage limits above are hard; public read abuse is monitored and coarse-limited separately.