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

# Storage

> Project object storage. Uploads and downloads happen through short-lived signed URLs; keys are tenant-relative and isolated per project. Operations address the project's original per-environment scope by default, or one named bucket via ?bucket= (see the buckets resource).

Project object storage. Uploads and downloads happen through short-lived signed URLs; keys are tenant-relative and isolated per project. Operations address the project's original per-environment scope by default, or one named bucket via ?bucket= (see the buckets resource).

## storage.list

List the environment's stored objects, optionally under a key prefix. Non-production environments keep their objects under an isolated scope; production keeps the project's original scope for back-compat, so production listings also surface other environments' objects under environment-named prefixes.

```text theme={null}
GET /v1/orgs/{orgId}/projects/{projectId}/storage
```

* **Auth:** Organization API key (`Authorization: Bearer korve_...`) or dashboard session.
* **Minimum role:** `member`
* **Risk:** `read`

### Query parameters

| Name          | Type   | Required | Description                        |
| ------------- | ------ | -------- | ---------------------------------- |
| `prefix`      | string | No       | —                                  |
| `environment` | string | No       | Pattern: `^[a-z][a-z0-9-]{0,38}$`. |
| `bucket`      | string | No       | Pattern: `^[a-z][a-z0-9-]{1,61}$`. |

### Example

```bash theme={null}
curl "https://api.korve.dev/v1/orgs/$ORG_ID/projects/$PROJECT_ID/storage?prefix=uploads%2F" \
  -H "Authorization: Bearer korve_..."
```

### Responses

| Status | Description                                                   |
| ------ | ------------------------------------------------------------- |
| `200`  | Objects with tenant-relative keys.                            |
| `404`  | No such project, environment, or bucket in this organization. |

### Response body (200)

| Field                  | Type      | Description                 |
| ---------------------- | --------- | --------------------------- |
| `objects`              | object\[] | —                           |
| `objects[].key`        | string    | Tenant-relative object key. |
| `objects[].size`       | integer   | Object size in bytes.       |
| `objects[].uploadedAt` | string    | Format: `date-time`.        |

## storage.createUpload

Create a short-lived signed URL for uploading one object to the addressed environment (production by default).

```text theme={null}
POST /v1/orgs/{orgId}/projects/{projectId}/storage/uploads
```

* **Auth:** Organization API key (`Authorization: Bearer korve_...`) or dashboard session.
* **Minimum role:** `member`
* **Billing:** requires active organization billing — returns `402` otherwise.
* **Risk:** `write` · sensitive (elevated blast radius)

### Query parameters

| Name          | Type   | Required | Description                        |
| ------------- | ------ | -------- | ---------------------------------- |
| `environment` | string | No       | Pattern: `^[a-z][a-z0-9-]{0,38}$`. |
| `bucket`      | string | No       | Pattern: `^[a-z][a-z0-9-]{1,61}$`. |

### Request body

| Field         | Type    | Required | Description                        |
| ------------- | ------- | -------- | ---------------------------------- |
| `filename`    | string  | Yes      | —                                  |
| `contentType` | string  | Yes      | —                                  |
| `byteLength`  | integer | Yes      | Exact size of the upload in bytes. |

### Example

```bash theme={null}
curl -X POST "https://api.korve.dev/v1/orgs/$ORG_ID/projects/$PROJECT_ID/storage/uploads?environment=example" \
  -H "Authorization: Bearer korve_..." \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "report.pdf",
  "contentType": "application/pdf",
  "byteLength": 24576
}'
```

### Responses

| Status | Description                                                       |
| ------ | ----------------------------------------------------------------- |
| `201`  | Signed upload. PUT the object bytes to the URL before it expires. |
| `402`  | Organization billing is not active.                               |
| `404`  | No such project, environment, or bucket in this organization.     |
| `422`  | Invalid filename, content type, or byte length.                   |

### Response body (201)

| Field       | Type   | Description                                                           |
| ----------- | ------ | --------------------------------------------------------------------- |
| `key`       | string | Tenant-relative key the object lands under.                           |
| `url`       | string | —                                                                     |
| `method`    | string | One of: `PUT`.                                                        |
| `headers`   | object | Headers that must accompany the upload request. Map of string values. |
| `expiresAt` | string | Format: `date-time`.                                                  |

## storage.getDownload

Create a short-lived signed URL for downloading one object from the addressed environment (production by default).

```text theme={null}
POST /v1/orgs/{orgId}/projects/{projectId}/storage/downloads
```

* **Auth:** Organization API key (`Authorization: Bearer korve_...`) or dashboard session.
* **Minimum role:** `member`
* **Risk:** `write`

### Query parameters

| Name          | Type   | Required | Description                        |
| ------------- | ------ | -------- | ---------------------------------- |
| `environment` | string | No       | Pattern: `^[a-z][a-z0-9-]{0,38}$`. |
| `bucket`      | string | No       | Pattern: `^[a-z][a-z0-9-]{1,61}$`. |

### Request body

| Field | Type   | Required | Description                 |
| ----- | ------ | -------- | --------------------------- |
| `key` | string | Yes      | Tenant-relative object key. |

### Example

```bash theme={null}
curl -X POST "https://api.korve.dev/v1/orgs/$ORG_ID/projects/$PROJECT_ID/storage/downloads?environment=example" \
  -H "Authorization: Bearer korve_..." \
  -H "Content-Type: application/json" \
  -d '{
  "key": "uploads/report.pdf"
}'
```

### Responses

| Status | Description                                                   |
| ------ | ------------------------------------------------------------- |
| `200`  | Signed download.                                              |
| `404`  | No such project, environment, or bucket in this organization. |
| `422`  | Missing or invalid key.                                       |

### Response body (200)

| Field       | Type   | Description          |
| ----------- | ------ | -------------------- |
| `url`       | string | —                    |
| `expiresAt` | string | Format: `date-time`. |

## storage.delete

Delete one object from the addressed environment (production by default). The key is the tenant-relative key, URL-encoded as a single path segment (encode "/" as "%2F").

```text theme={null}
DELETE /v1/orgs/{orgId}/projects/{projectId}/storage/objects/{key}
```

* **Auth:** Organization API key (`Authorization: Bearer korve_...`) or dashboard session.
* **Minimum role:** `admin`
* **Risk:** `destructive`

### Path parameters

| Name  | Type   | Required | Description |
| ----- | ------ | -------- | ----------- |
| `key` | string | Yes      | —           |

### Query parameters

| Name          | Type   | Required | Description                        |
| ------------- | ------ | -------- | ---------------------------------- |
| `environment` | string | No       | Pattern: `^[a-z][a-z0-9-]{0,38}$`. |
| `bucket`      | string | No       | Pattern: `^[a-z][a-z0-9-]{1,61}$`. |

### Example

```bash theme={null}
curl -X DELETE "https://api.korve.dev/v1/orgs/$ORG_ID/projects/$PROJECT_ID/storage/objects/uploads%2Freport.pdf?environment=example" \
  -H "Authorization: Bearer korve_..."
```

### Responses

| Status | Description                                                   |
| ------ | ------------------------------------------------------------- |
| `200`  | Object deleted (idempotent).                                  |
| `404`  | No such project, environment, or bucket in this organization. |
