Shukr Docs
Shukr Public Media Service

Overview

What the Shukr Public Media Service does, how assets flow through it, and how the API is shaped.

The Shukr Public Media Service is a Cloudflare Workers microservice (Hono + Zod) that manages media assets for the Shukr/Barakah ecosystem. It never proxies file bytes: clients upload and download directly to object storage (Cloudflare R2) through short-lived presigned URLs, and videos are handed off to a streaming provider for transcoding and delivery.

What it does

Two kinds of asset

Every record has an asset_kind that decides its entire lifecycle:

asset_kindStored inDelivered asProviders
fileCloudflare R2Presigned GET URL
streamStreaming provider (video)HLS/DASH playback + thumbnailbunny, cloudflare, onprem

Images, audio, and other plain files are file assets. Videos are stream assets: the service routes them to a provider, the provider transcodes, then calls back via a webhook to mark the asset ready. See Concepts for the full data model.

Who uses it

Other Shukr services call this API to store and serve their media. The content_type field (place or post) records what the media belongs to:

Scenariocontent_typeasset_kindExample
Places (Maps)placefile / streamPhotos and videos of a location — venue galleries, a place walkthrough.
Posts / feedback / notespostfile / streamImages or files attached to a user post, a location's feedback, or a note about a place.
Video contenteitherstreamAny clip needing adaptive HLS/DASH playback (auto-selected by a video/* MIME type).
Generic file storageeitherfileAudio, PDFs, or any allowed file type another service wants stored and served via presigned URLs.

Each endpoint page spells out what it does, when to reach for it, how to call it, and its scope (auth + ownership).

Base URL

All business endpoints are versioned under /api/v1. Health lives at the root.

# Route through the gateway; replace with your deployment host.
https://media.example.com/api/v1

Examples in these docs use https://media.example.com as the base URL and the placeholder asset id 550e8400-e29b-41d4-a716-446655440000. Substitute your own host and ids.

Response envelope

Every JSON endpoint wraps its payload in a consistent envelope. The endpoint-specific shape always lives under data.

{
  "success": true,
  "message": "Media asset retrieved",
  "code": 200,
  "data": { "asset": { "id": "550e8400-e29b-41d4-a716-446655440000" } },
  "request_id": "req_01J9Z0X8Q2",
  "timestamp": "2026-07-29T04:15:30.000Z"
}

The request_id is echoed on every response (and set as a response header) so you can correlate a client call with server logs.

Playback delivery endpoints are the exception — they return raw manifests, HTML, or 302 redirects, not the JSON envelope. See Playback & streaming.

The typical lifecycle

  1. Request an uploadPOST /api/v1/media/upload-url creates a pending asset and returns presigned upload instructions.
  2. Upload the bytes — PUT directly to R2 (single/multipart), or resumable-upload to the provider (TUS).
  3. CompletePOST /api/v1/media/{id}/complete verifies the upload and flips the asset to uploaded.
  4. Transcode (video only) — the provider processes the video and calls a webhook; stream_status moves pending_upload → processing → ready.
  5. DeliverPOST /api/v1/media/{id}/download-url for files, or the playback endpoints for video.

Health

curl https://media.example.com/health
{
  "success": true,
  "message": "Service is healthy",
  "code": 200,
  "data": { "status": "ok", "service": "shukr-public-media-service" },
  "request_id": "req_01J9Z0X8Q2",
  "timestamp": "2026-07-29T04:15:30.000Z"
}

Next steps

  • Authentication — JWT vs service key, and ownership rules.
  • Concepts — the asset model, upload modes, and stream lifecycle.
  • API Reference — the interactive, always-in-sync endpoint reference.

On this page