Shukr Docs
Shukr Public Media Service

Downloads

Resolve time-limited download URLs for file assets — one asset at a time, or many in a single batched call.

Download endpoints return presigned GET URLs for file assets. For stream (video) assets they return playback information instead — a single endpoint covers both kinds so you don't need to branch before calling.

Both endpoints require authentication and can return 400 / 401 / 403 / 404 / 500.


Create a download URL

POST /api/v1/media/{id}/download-url200 OK

What it is — Returns a time-limited link for one asset: a presigned GET URL for a file, or playback info for a video. One endpoint handles both kinds.

When to use it — Serving a single stored item to a client: display a place photo, download a note's file attachment, or start playing a feedback video.

How to use it — POST (optionally set expires_in). Then:

  • File asset → open/download download_url (a presigned R2 GET).
  • Stream asset → use playback (when stream_status is ready); on-prem streams also include a download_url for the source file in R2.

Scope — Token owner or service key. The asset must be uploaded.

Request body

Optional:

FieldTypeNotes
expires_ininteger (60–86400)URL lifetime in seconds. Defaults to R2_SIGNED_URL_EXPIRY (3600).
curl -X POST https://media.example.com/api/v1/media/550e8400-e29b-41d4-a716-446655440000/download-url \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "expires_in": 900 }'

Batch download URLs

POST /api/v1/media/download-urls200 OK

What it is — Resolves download URLs / playback for many assets in one round-trip, with partial success.

When to use it — Rendering a gallery or feed: every photo of a Maps place, all attachments on a post, or a mixed list of files and videos — without a request per item.

How to use it — POST asset_ids (≤ 50). The call returns 200 even if some assets fail — inspect each item's error. Items come back in input order.

ScopeUser token (own assets only) or service key (owner_user_id required).

This is partial-success: the call returns 200 even if some assets fail, and each item carries its own error.

Request body

FieldTypeRequiredNotes
asset_idsuuid[]1–100 ids (deduped). Capped by BATCH_MEDIA_MAX_ASSETS (default 50).
owner_user_idstring (1–255)⚠️Required for service-key callers.
expires_ininteger (60–86400)Applied to every resolved URL.

Each item mirrors the single-download shape plus an error field, one of: not_found, forbidden, not_ready, not_stream, or null on success.

curl -X POST https://media.example.com/api/v1/media/download-urls \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "asset_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "770e8400-e29b-41d4-a716-4466554400ff"
    ],
    "expires_in": 900
  }'

Always inspect each item's error — a 200 on the envelope does not mean every asset resolved. not_ready means a stream asset is still transcoding; retry after its webhook fires.

On this page