---
title: "Generate a time-limited presigned GCS download URL"
method: GET
path: "/storage/presigned-url"
tags: ["Storage"]
---

# Generate a time-limited presigned GCS download URL

`GET /storage/presigned-url`

Returns a presigned URL that grants direct, unauthenticated read access to a single GCS object for up to 1 hour.

When to use: Choose this endpoint when the file consumer cannot present API credentials at download time — for example, a browser-side redirect or a third-party client. For server-to-server transfers where credentials are available, use GET /storage/download instead.

Preconditions: Requires the STORAGE_READ permission in addition to a valid JWT. The filePath parameter accepts either a plain relative path (e.g. documents/report.pdf) or a full GCS URI (gs://bucket-name/documents/report.pdf); both forms are supported here. Paths undergo sanitization: values containing path-traversal sequences (../), leading slashes, backslashes, repeated slashes (//), or the characters <>:"|?* are rejected with 400. Multi-segment paths are also rejected with 400 when the first path segment contains a dot or is exactly "file" (e.g. reports.q1/data.csv, file/report.pdf).

Response: On success, returns a presigned URL and an expiresAtTimestamp indicating when the URL expires. The URL requires no further API authentication — share it directly with the consumer. No files are modified; this operation has no side effects.

## Query parameters

- `filePath` string, required

## Headers

- `tenant-id` string, required

## Response `200`

Presigned download URL and its expiry timestamp. The URL grants direct GCS read access with no further API authentication required.

- PresignedUrlResponse
  - `presignedUrl` string — Presigned URL for downloading the file
  - `expiresInHours` integer — Number of hours until the URL expires
  - `expiresAtTimestamp` integer — Unix timestamp when the URL expires

## Other responses

- `400` — The filePath was missing, malformed, or rejected by path sanitization (path traversal, leading slash, or illegal characters). Correct the path and retry.
- `401` — The request lacked a valid JWT. Authenticate and retry.
- `403` — The authenticated caller lacks the STORAGE_READ permission required for this operation.
- `404` — No object exists at the resolved bucket and path. Verify the file was uploaded and the path is correct.
- `500` — Presigned URL generation failed unexpectedly (e.g. a GCS signing error). Retry; if the problem persists, contact support.

---

[API](https://skmtc.net/certifyos/apis/certify-api-layer.md) · [All operations](https://skmtc.net/certifyos/apis/certify-api-layer/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/certifyos/certify-api-layer/revisions/563848e0ecc0/schema)
