# Archive (unpublish) a video Source: https://developers.myeden.me/api-reference/videos/archive-unpublish-a-video /openapi.yaml post /v1/videos/{id}/archive Hides the video from feeds, search, and recommendations while preserving the asset. Reversible via `/v1/videos/{id}/republish`. If called while the video is still processing, archive intent is queued and the video will be created in an archived state. Requires the `videos:write` scope. # Delete a video Source: https://developers.myeden.me/api-reference/videos/delete-a-video /openapi.yaml delete /v1/videos/{id} Permanently deletes the video from Eden. Removes the Mux asset, QuickBlox Clips object, GetStream feed activity, Recombee item, and search index entry. This action is irreversible. If called while the video is still processing, the delete is queued and executed when processing completes. Requires the `videos:write` scope. # Get video status and playback details Source: https://developers.myeden.me/api-reference/videos/get-video-status-and-playback-details /openapi.yaml get /v1/videos/{id} Returns the current status of an ingested video. While processing, only basic fields are populated. Once `status` is `ready` and `is_available` is `true`, the `playback` object contains Mux IDs and HLS URL. Requires the `videos:read` scope. # Ingest a video from a public URL Source: https://developers.myeden.me/api-reference/videos/ingest-a-video-from-a-public-url /openapi.yaml post /v1/videos Submits a publicly accessible video URL for ingestion. Responds immediately with `202 Accepted` and an `id`. Use that `id` to check status, archive, republish, or delete. Requires the `videos:write` scope. # Republish an archived video Source: https://developers.myeden.me/api-reference/videos/republish-an-archived-video /openapi.yaml post /v1/videos/{id}/republish Reverses `archive`: video is re-indexed across feeds, search, and recommendations. Requires the `videos:write` scope. # Authentication Source: https://developers.myeden.me/authentication How API keys work and how to keep them safe. The Eden API uses **API keys** sent as Bearer tokens. ## Key format ``` eden_live__ ``` * `eden_live_` — fixed prefix * `keyId` — 24 characters, uniquely identifies the key * `secret` — 32 characters, kept private The full key is shown to you **once** when issued. Eden stores only a salted hash — if you lose it, we can't recover it; we can only issue a new one. ## Sending the key ```http theme={null} GET /v1/videos/vid_a7Kp9m... HTTP/1.1 Host: api.myeden.me Authorization: Bearer eden_live_a7Kp9mNqR2vXyB4dH6jL8sTw_M3nP5qR7sT9vW2xY4zA6bC8dE0fG2hJ ``` ## Scopes | Scope | Allows | | -------------- | ---------------------------------- | | `videos:read` | Get video status and details | | `videos:write` | Ingest, archive, republish, delete | Request a read-only key for analytics integrations — safer than reusing a write key. ## How keys map to content Each API key is bound to one Eden publisher account. Every video you ingest is owned by that publisher account. If you rotate keys (revoke an old one, issue a new one) videos created by the old key remain manageable by any new key tied to the same publisher account. If your organization needs multiple isolated key spaces (e.g. separate keys for live game ingest vs. archival content), contact us and we'll set up separate publisher accounts. ## Security best practices Keep keys on your backend. Embedding in mobile or web clients effectively makes them public. Load keys from environment variables. `.env` belongs in `.gitignore`. Request distinct keys for staging and production. Email [support@myeden.me](mailto:support@myeden.me) to rotate immediately if compromised. The old key is revoked the moment the new one is issued. ## Requesting access API access is invite-only. Email [support@myeden.me](mailto:support@myeden.me?subject=API%20Access%20Request) with your organization name and intended use case. # Errors Source: https://developers.myeden.me/errors Error envelope, status codes, and how to debug. All errors share the same envelope: ```json theme={null} { "error": { "code": "invalid_input", "message": "source_url must be an HTTPS URL", "request_id": "req_a1b2c3d4e5f6" } } ``` Include the `request_id` (also returned in the `x-request-id` response header) when contacting support. ## Status codes | Status | When you'll see it | | ------------------------- | ------------------------------------------------------- | | `400 invalid_input` | Body validation failed. | | `401 missing_credentials` | No `Authorization` header. | | `401 invalid_credentials` | Key is malformed, unknown, or revoked. | | `403 insufficient_scope` | Key doesn't have the required scope. | | `404 not_found` | Video doesn't exist or belongs to another organization. | | `429 rate_limited` | RPM exceeded. Wait `retry-after` seconds. | | `429 daily_ingest_limit` | Daily ingest budget exhausted. | | `500 internal_error` | Eden-side problem. Retry with backoff. | 404 vs 403: we return 404 when a video belongs to a different organization so we don't reveal the existence of other partners' content. ## Retry strategy | Code | Retry? | | ---- | ---------------------------------------------------- | | 4xx | No — fix the request first. | | 429 | Yes — after `retry-after` seconds. | | 5xx | Yes — exponential backoff with jitter, \~5 attempts. | Reasonable backoff: 1s, 2s, 4s, 8s, 16s (each with ±25% jitter). # Analytics via BigQuery Source: https://developers.myeden.me/guides/analytics-via-bigquery Direct access to your video performance data. Eden does not offer a REST analytics endpoint. Instead, we provide **direct BigQuery access** to your video performance data, sourced from Mux Data. This is intentionally more powerful than a REST endpoint: you get raw view events, audience demographics, playback quality, geographic breakdowns, and full SQL access to slice the data any way you want. ## What's available Per video: * View count, unique viewers, total watch time * Geographic distribution * Device and platform breakdown * Playback failures and rebuffering rates * Engagement (% watched, drop-off points) Per organization: * Aggregated metrics across your catalog * Time-series performance trends * Top-performing content ## Getting access 1. Email [support@myeden.me](mailto:support@myeden.me) with your organization's Google Cloud account or BigQuery dataset where you'd like access 2. Eden grants IAM read access on a per-org authorized view that filters to your videos only 3. You query the view from your BigQuery console, Looker, Tableau, or any tool that connects to BigQuery ## Example query ```sql theme={null} SELECT external_id AS video_id, COUNT(DISTINCT viewer_id) AS unique_viewers, SUM(playing_time) / 3600 AS hours_watched, AVG(playback_score) AS avg_quality FROM `eden-analytics.partner_views.your_org_id` WHERE event_date >= CURRENT_DATE() - 30 GROUP BY video_id ORDER BY hours_watched DESC LIMIT 100; ``` ## Update frequency View events stream into BigQuery within 5 minutes of occurring. Historical data goes back to your organization's first video. BigQuery access is provisioned manually. If you don't see your dataset yet, email [support@myeden.me](mailto:support@myeden.me). # Archive and republish Source: https://developers.myeden.me/guides/archive-and-republish Pull videos from feeds temporarily without deleting them. Archive removes a video from feeds, search, and recommendations without losing the asset or any history. Republish puts it back. Use archive for embargo windows, content rotation, or temporary takedowns during reviews. Use `DELETE` only for permanent removal. ## Archive ```bash theme={null} curl -X POST https://api.myeden.me/v1/videos/vid_a7Kp9m.../archive \ -H "Authorization: Bearer $EDEN_API_KEY" ``` Response: ```json theme={null} { "id": "vid_a7Kp9m...", "status": "archived" } ``` After archiving: * The video is no longer returned in any feed * Search excludes it * Recommendations re-rank to remove it * Direct playback links continue to work for \~5 minutes (CDN cache), then return 404 to viewers * The underlying Mux asset and captions are preserved ## Republish ```bash theme={null} curl -X POST https://api.myeden.me/v1/videos/vid_a7Kp9m.../republish \ -H "Authorization: Bearer $EDEN_API_KEY" ``` Response: ```json theme={null} { "id": "vid_a7Kp9m...", "status": "public" } ``` Republishing re-indexes the video across feeds, search, and recommendations within \~60 seconds. ## Archiving a video that's still processing You can call `archive` on a video that's still processing. The archive intent is queued, and the video will be created in an archived state when processing completes — meaning it never appears in feeds. Useful if you realize mid-pipeline that the content shouldn't be live. Response (queued archive): ```json theme={null} { "id": "vid_a7Kp9m...", "status": "archive_queued", "message": "Video is still processing. It will be archived when ready." } ``` ## Archive vs delete | | Archive | Delete | | ------------------- | ---------------------------------------- | ----------------- | | Reversible | Yes (`republish`) | No | | Mux asset preserved | Yes | No | | Captions preserved | Yes | No | | Use for | Embargoes, rotation, temporary takedowns | Permanent removal | # Checking status Source: https://developers.myeden.me/guides/checking-status How to know when a video is live. After `POST /v1/videos`, your video is processing. To know when it's live, poll `GET /v1/videos/{id}`. A video is live when: * `status` is `"ready"` * `is_available` is `true` * `playback` contains a `playback_id` ## Suggested polling schedule Short videos finish in 90 seconds; full games can take 30 minutes. Exponential backoff works well: | Attempt | Wait before | | ------- | ------------ | | 1 | 10s | | 2 | 20s | | 3 | 40s | | 4 | 80s | | 5+ | 120s, capped | Stop polling once `status` is `ready`, `archived`, or `deleted`. ```javascript theme={null} async function waitForReady(videoId, apiKey, { maxAttempts = 25 } = {}) { for (let i = 0; i < maxAttempts; i++) { const wait = Math.min(10_000 * 2 ** i, 120_000); await new Promise((r) => setTimeout(r, wait)); const res = await fetch(`https://api.myeden.me/v1/videos/${videoId}`, { headers: { Authorization: `Bearer ${apiKey}` }, }); if (!res.ok) throw new Error(`status check failed: ${res.status}`); const body = await res.json(); if (body.status === 'ready' && body.is_available) return body; if (body.status === 'deleted') throw new Error('Video was deleted'); } throw new Error('timeout waiting for video to become ready'); } ``` ## Coming in v1.1: webhooks Polling works, but webhooks are better. We're shipping `video.ready` and `video.failed` webhooks in v1.1. Email [support@myeden.me](mailto:support@myeden.me) to be added to the early-access list. # Ingesting videos Source: https://developers.myeden.me/guides/ingesting-videos Best practices for the POST /v1/videos endpoint. ## Source URL requirements * Must be HTTPS * Must be publicly accessible (no cookie auth, no short-expiry signed URLs) * Container: mp4, mov, mkv, webm * Codec: H.264 / H.265 / VP9 / AV1 * Recommended max duration: 4 hours * Recommended max size: 5 GB If your CDN requires signed URLs, generate one valid for at least 30 minutes so Eden's pipeline has time to fetch. ## Custom thumbnails The optional `thumbnail_url` parameter lets you supply your own promotional image for each video. If omitted, Mux generates one automatically from a frame in the video. **Recommended specs:** * Aspect ratio: **16:9** (e.g. 1920×1080, 1280×720) * Format: JPEG or PNG * Max size: 2 MB * Must be HTTPS and publicly accessible **Example request with custom thumbnail:** ```json theme={null} { "source_url": "https://media.example.com/highlight.mp4", "thumbnail_url": "https://media.example.com/highlight-thumb.jpg", "title": "Q4 Game-Winning Shot", "tags": ["highlights", "finals"] } ``` The thumbnail URL is stored as-is and served directly from your CDN. Eden does not download or proxy the image, so make sure your CDN can handle the expected traffic to the URL. If you change the thumbnail later, currently you'd need to delete and re-ingest the video. Per-video thumbnail updates are planned for v1.1. ## Sport The `sport` field links your video to one of Eden's sport-specific feeds and surfaces. It is optional but strongly recommended — videos with a sport tag get better placement in personalized recommendations. | Value | Sport | | --------------------- | ------------------- | | `tennis` | Tennis | | `soccer` | Soccer | | `basketball` | Basketball | | `cricket` | Cricket | | `american_football` | American Football | | `australian_football` | Australian Football | | `baseball` | Baseball | | `lacrosse` | Lacrosse | | `badminton` | Badminton | | `equestrian` | Equestrian | | `golf` | Golf | | `boxing` | Boxing | | `mma` | Mixed Martial Arts | | `formula_one` | Formula 1 | | `ice_hockey` | Ice Hockey | | `rugby` | Rugby | | `cycling` | Cycling | | `track_and_field` | Track & Field | | `swimming` | Swimming | | `gymnastics` | Gymnastics | | `table_tennis` | Table Tennis | | `skiing` | Skiing | | `snowboarding` | Snowboarding | | `skateboarding` | Skateboarding | | `surfing` | Surfing | | `wrestling_pro` | Wrestling (Pro) | | `motocross` | Motocross | | `fencing` | Fencing | | `climbing` | Climbing | | `pickleball` | Pickleball | Sending an unknown `sport` value returns `400 invalid_input`. If a sport you need is missing, contact developer support to have it added. ## Category The `category` field is YouTube-style content-type taxonomy and is **independent of the `sport` field**. They describe different dimensions: * `sport` identifies the sport the content is about (routes to sport-specific feeds) * `category` identifies the content type (entertainment, comedy, education, etc.) A tennis player's interview is `sport: "tennis"`, `category: "entertainment"`. A highlight reel is `sport: "tennis"`, `category: "sports"`. A behind-the-scenes training video is `sport: "tennis"`, `category: "howto_style"`. Both fields are optional but recommended — they power different discovery surfaces. | Value | Category | | -------------------- | --------------------- | | `autos_vehicles` | Autos & Vehicles | | `comedy` | Comedy | | `education` | Education | | `entertainment` | Entertainment | | `film_animation` | Film & Animation | | `gaming` | Gaming | | `howto_style` | Howto & Style | | `music` | Music | | `news_politics` | News & Politics | | `nonprofits` | Nonprofits & Activism | | `people_blogs` | People & Blogs | | `pets_animals` | Pets & Animals | | `science_technology` | Science & Technology | | `sports` | Sports | | `travel_events` | Travel & Events | ## Language code The `language_code` field tells Mux's caption generation what language the source video's audio is in. Defaults to `en` if omitted. **Format**: lowercase ISO 639-1 two-letter code only. Examples: `en`, `es`, `fr`, `de`, `pt`, `ja`, `zh`, `ar`. Country variants like `en-US` are **not accepted** — send the base language code only. Eden auto-translates captions into 18 additional languages regardless of source — partners only need to send the source language correctly. ## Summary The `summary` field is an optional text description of the video. Use it to capture your editorial blurb, press release snippet, or game recap — anything you'd want to surface alongside the title in feeds, search results, and recommendations. **Constraints:** * Maximum length: 2000 characters * Format: plain text (no HTML, no markdown rendering — special characters are preserved as-is) * Optional. Videos without a summary still index normally; the field simply stays null. If a summary is provided, it persists in both QuickBlox (powering the in-app display) and Recombee (powering search and recommendation ranking). Longer-form context generally improves recommendation match quality, so sending a meaningful summary is encouraged for highlight reels, interviews, and feature content. Short clips (raw plays, 10-second moments) can safely omit it. ## What happens after you POST 1. **Mux fetches** your video from `source_url` directly 2. **Mux** transcodes the video for adaptive bitrate streaming 3. **Mux AI** generates captions and translates them into 18 languages 4. **Azure Video Indexer** extracts metadata (topics, labels, scenes) 5. **Eden's discovery layer** indexes the video across feeds, search, and recommendations Total time depends on duration. Short clips (under 2 minutes) complete in \~90 seconds; full games can take 30+ minutes. ## Trust & safety The Developer API does not run UGC content moderation. As an invited partner, you've agreed to Eden's content policy and warrant that all videos uploaded comply with it. Eden may review, archive, or remove content that violates policy. If you discover content that should be removed, use `POST /v1/videos/{id}/archive` (reversible) or `DELETE /v1/videos/{id}` (permanent). ## Idempotency The API is not automatically idempotent. POSTing the same `source_url` twice creates two videos. Deduplicate on your side before calling. ## Common mistakes If your CDN serves a partial file, transcoding will fail. Wait until your upload pipeline confirms the asset is complete. `source_url` must start with `https://`. HTTP is rejected with `400 invalid_input`. Mux fetches the video directly from your URL. If your CDN blocks requests from Mux's fetcher (rotating IPs, mostly US-based) the ingest will fail. The simplest fix: serve the video from a URL with no geo or IP restrictions. If you need to whitelist specific IPs, reach out and we'll share Mux's current ingress ranges. Public URL means publicly accessible. If your CDN requires headers or cookies, Eden's fetcher won't be able to authenticate. Use a signed URL with a long enough TTL instead. # Introduction Source: https://developers.myeden.me/introduction Distribute brand and athlete video content on Eden via API. The Eden Developer API lets brands, leagues, teams, and rights-holding organizations publish video content on Eden — the athlete creator platform — directly from their CDN, without using the Eden app. This is an **invite-only API** available to partners with an active distribution agreement with Eden. Contact [support@myeden.me](mailto:support@myeden.me?subject=API%20Access%20Request) to request access. ## What you can do * Ingest highlights, full games, or original programming from a public URL * Archive videos to temporarily pull them from feeds * Republish archived videos when an embargo lifts * Delete videos permanently across Eden and downstream services * Check status while videos process Videos go live across Eden's iOS, tvOS, Android, and web apps once processing completes (typically 2–5 minutes). Make your first API call in five minutes. API keys and how to keep them safe. Full reference for every endpoint. Direct BigQuery access to your video performance data. # Quickstart Source: https://developers.myeden.me/quickstart Ingest your first video in five minutes. ## 1. Set your API key ```bash macOS / Linux theme={null} export EDEN_API_KEY="eden_live_xxxxxxxxxxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" ``` ```powershell Windows theme={null} $env:EDEN_API_KEY = "eden_live_xxxxxxxxxxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" ``` Treat your API key like a password. Never embed it in client code or commit it to source control. ## 2. Submit a video ```bash cURL theme={null} curl -X POST https://api.myeden.me/v1/videos \ -H "Authorization: Bearer $EDEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source_url": "https://cdn.example.com/highlights/game-7.mp4", "title": "Game 7 — Final Two Minutes", "tags": ["nba", "playoffs"], "sport": "basketball" }' ``` ```javascript Node.js theme={null} const res = await fetch('https://api.myeden.me/v1/videos', { method: 'POST', headers: { Authorization: `Bearer ${process.env.EDEN_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ source_url: 'https://cdn.example.com/highlights/game-7.mp4', title: 'Game 7 — Final Two Minutes', tags: ['nba', 'playoffs'], sport: 'basketball', }), }); const { id } = await res.json(); console.log('Ingested', id); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.myeden.me/v1/videos", headers={"Authorization": f"Bearer {os.environ['EDEN_API_KEY']}"}, json={ "source_url": "https://cdn.example.com/highlights/game-7.mp4", "title": "Game 7 — Final Two Minutes", "tags": ["nba", "playoffs"], "sport": "basketball", }, ) print(res.json()) ``` Response: ```json theme={null} { "id": "vid_a7Kp9mNqR2vXyB4dH6jL8s", "status": "processing", "resource_url": "/v1/videos/vid_a7Kp9mNqR2vXyB4dH6jL8s", "message": "Video accepted. It typically takes 2–5 minutes to become available." } ``` **Save the `id`.** You'll use it to check status, archive, republish, or delete this video. Store it in your CMS alongside the source URL. ## 3. Check status ```bash theme={null} curl https://api.myeden.me/v1/videos/vid_a7Kp9m... \ -H "Authorization: Bearer $EDEN_API_KEY" ``` While processing: ```json theme={null} { "id": "vid_a7Kp9mNqR2vXyB4dH6jL8s", "status": "processing", "is_available": false, "title": "Game 7 — Final Two Minutes", "tags": ["nba", "playoffs"], "playback": null, "created_at": "2026-05-22T14:30:00Z" } ``` When ready: ```json theme={null} { "id": "vid_a7Kp9mNqR2vXyB4dH6jL8s", "status": "ready", "is_available": true, "title": "Game 7 — Final Two Minutes", "duration_seconds": 124, "playback": { "playback_id": "abc123XYZ", "hls_url": "https://stream.mux.com/abc123XYZ.m3u8", "thumbnail_url": "https://image.mux.com/abc123XYZ/thumbnail.jpg" }, "created_at": "2026-05-22T14:30:00Z", "updated_at": "2026-05-22T14:33:12Z" } ``` The video is now live on Eden across iOS, tvOS, Android, and web. Playback URLs require a signed token to play. The Eden apps handle this automatically. If you need to embed playback elsewhere, contact Eden for details on the token-signing flow. # Rate limits Source: https://developers.myeden.me/rate-limits Per-key request and ingest limits. Each API key has two independent limits: | Limit | Default | Header | | ----------------------- | ------- | ----------------------------- | | Requests per minute | 60 | `x-ratelimit-remaining` | | Ingest requests per day | 500 | `x-ratelimit-daily-remaining` | Default limits are intentionally conservative for v1. Email [support@myeden.me](mailto:support@myeden.me) with your expected volume and we'll raise them. The daily header is only returned on `POST /v1/videos` — status checks and archive/republish/delete don't count against the daily ingest budget. ## When you hit a limit ```http theme={null} HTTP/1.1 429 Too Many Requests retry-after: 42 { "error": { "code": "rate_limited", "message": "Request rate exceeded. See retry-after header.", "request_id": "req_a1b2c3d4e5f6" } } ``` The `code` is `rate_limited` for RPM violations and `daily_ingest_limit` for daily budget violations. ## Best practices * Respect `retry-after`. Add exponential backoff with jitter. * For bulk catalog imports, spread ingest across the day or coordinate a temporary limit increase in advance. * Reuse HTTP connections — keep-alive reduces cold-start latency.