The SDK has one billable event type: stream acquisition. Browsing, searching, library reads, and metadata fetches do not bill. The two RPCs that matter are:Documentation Index
Fetch the complete documentation index at: https://docs.sdk.anghami.com/llms.txt
Use this file to discover all available pages before exploring further.
StreamingService.AcquireMusicStream(song_id, max_quality)— billed as a music stream.StreamingService.AcquireVideoStream(movie_id | episode_id, max_quality)— billed as a video stream. The request carries aoneof content { MovieID movie_id; EpisodeID episode_id }.
stream scope. API keys cannot acquire streams.
What you get back
Each acquire returns aStreamInfo payload with:
manifest_url— the time-limited stream URL (HLS m3u8 or DASH mpd).expires_in_seconds— seconds remaining until the URL expires (relative, not an absolute timestamp).drm_scheme,license_url,drm_params— DRM metadata when the stream is protected.drm_schemeisDRM_SCHEME_UNSPECIFIEDfor clear streams.drm_paramsis a string→string map of scheme-specific values (e.g.certificate_urlfor FairPlay).available_qualities— the quality tiers the server actually exposes for this stream (each entry is aQualityOption { label, bitrate_kbps, codec }). The server may pick a tier below the requestedmax_qualityif the user is not entitled to it.
expires_in_seconds. Re-acquire to get a fresh URL. Re-acquiring within the lifetime of an existing URL does not re-bill — it returns a fresh signed URL for the same logical stream.
What counts as a billable event
| Event | Billable? |
|---|---|
First AcquireMusicStream for (user, song) in a session | Yes |
Re-acquiring the same (user, song) while the prior URL is still valid | No (same logical stream) |
| Re-acquiring after URL expiry | Yes (new logical stream) |
| Acquiring for a different song | Yes |
| Acquiring at a different quality for the same song | Yes |
GetSong, Search, BrowseCharts, … | Never |
No playback reporting
There is noReportPlaybackStart / ReportPlaybackEnd / ReportPlaybackProgress RPC, by design. The billable event is the acquire, not the play. This keeps the SDK simple and the billing contract unambiguous: if your client acquires a stream, that’s the event, regardless of whether the user actually pressed play.
Concurrency
Stream acquisition has its own concurrency cap separate from request-rate limits — the cap is per OAuth user, not per API key. Exceeding it returnsERROR_CODE_PERMISSION_DENIED with a message indicating concurrent stream limits. This is enforced at the entitlement layer, not the rate-limit layer.
DRM
Whendrm_scheme is anything other than DRM_SCHEME_UNSPECIFIED, the client must:
- Read
drm_scheme— one ofDRM_SCHEME_FAIRPLAY(Apple FairPlay),DRM_SCHEME_WIDEVINE(Google Widevine),DRM_SCHEME_PLAYREADY(Microsoft PlayReady), orDRM_SCHEME_CLEARKEY(W3C Clear Key, test scenarios only). - POST a license request to
license_urlwith the platform-specific key request body.license_urlis empty forCLEARKEYand unprotected streams. - Pass any scheme-specific values from
drm_params(e.g.certificate_urlfor FairPlay) into the platform DRM module before playback.
drm_scheme, license_url, and drm_params opaquely to the platform layer.
Best practices
- Acquire just-in-time. Don’t pre-acquire entire playlists; you’ll bill for streams the user never plays.
- Refresh on expiry, not eagerly. Honor
expires_in_secondsand only re-acquire when the URL is about to expire or has expired. - Surface acquire failures cleanly. A failed acquire is the right time to show DRM errors, region-restriction errors, or entitlement errors to the user.
- Use
max_qualitydeliberately. AcquiringAUDIO_QUALITY_HIGHfor a user only entitled toAUDIO_QUALITY_STANDARDis downgraded server-side — no separate negotiation step needed. Audio tiers:AUDIO_QUALITY_LOW,AUDIO_QUALITY_STANDARD,AUDIO_QUALITY_HIGH,AUDIO_QUALITY_LOSSLESS. Video tiers:VIDEO_QUALITY_SD,VIDEO_QUALITY_HD,VIDEO_QUALITY_FULL_HD,VIDEO_QUALITY_UHD.